Skip to content

Commit d8c9782

Browse files
author
Tanner Reits
committed
fix(overlays): focus management with checkbox & radio
1 parent 470decc commit d8c9782

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

core/src/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,7 @@ export namespace Components {
23032303
* The name of the control, which is submitted with the form data.
23042304
*/
23052305
"name": string;
2306+
"setFocus": () => Promise<void>;
23062307
/**
23072308
* the value of the radio group.
23082309
*/

core/src/components/radio-group/radio-group.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComponentInterface, EventEmitter } from '@stencil/core';
2-
import { Component, Element, Event, Host, Listen, Prop, Watch, h } from '@stencil/core';
2+
import { Component, Element, Event, Host, Listen, Method, Prop, Watch, h } from '@stencil/core';
33
import { renderHiddenInput } from '@utils/helpers';
44

55
import { getIonMode } from '../../global/ionic-global';
@@ -217,6 +217,13 @@ export class RadioGroup implements ComponentInterface {
217217
}
218218
}
219219

220+
/** @internal */
221+
@Method()
222+
async setFocus() {
223+
const radioToFocus = this.getRadios().find((r) => r.tabIndex !== -1);
224+
radioToFocus?.setFocus();
225+
}
226+
220227
render() {
221228
const { label, labelId, el, name, value } = this;
222229
const mode = getIonMode(this);

core/src/utils/focus-trap.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { focusVisibleElement } from '@utils/helpers';
1313
* valid usage for the disabled property on ion-button.
1414
*/
1515
export const focusableQueryString =
16-
'[tabindex]:not([tabindex^="-"]):not([hidden]):not([disabled]), input:not([type=hidden]):not([tabindex^="-"]):not([hidden]):not([disabled]), textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), button:not([tabindex^="-"]):not([hidden]):not([disabled]), select:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable[disabled="false"]:not([tabindex^="-"]):not([hidden])';
16+
'[tabindex]:not([tabindex^="-"]):not([hidden]):not([disabled]), input:not([type=hidden]):not([tabindex^="-"]):not([hidden]):not([disabled]), textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), button:not([tabindex^="-"]):not([hidden]):not([disabled]), select:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-checkbox:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-radio:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable[disabled="false"]:not([tabindex^="-"]):not([hidden])';
1717

1818
/**
1919
* Focuses the first descendant in a context
@@ -78,7 +78,14 @@ const focusElementInContext = <T extends HTMLElement>(
7878
}
7979

8080
if (elementToFocus) {
81-
focusVisibleElement(elementToFocus);
81+
// TODO: need to verify we're focusing a radio?
82+
const radioGroup = elementToFocus.closest('ion-radio-group');
83+
84+
if (radioGroup) {
85+
radioGroup.setFocus();
86+
} else {
87+
focusVisibleElement(elementToFocus);
88+
}
8289
} else {
8390
// Focus fallback element instead of letting focus escape
8491
fallbackElement.focus();

0 commit comments

Comments
 (0)