Skip to content

Commit 07b6a26

Browse files
committed
refactor(focusVisibleElement): add raf & comments
1 parent cf44ede commit 07b6a26

File tree

4 files changed

+36
-16
lines changed

4 files changed

+36
-16
lines changed

core/src/components.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ export namespace Components {
333333
*/
334334
"mode"?: "ios" | "md";
335335
/**
336-
* Used to set focus on an element that uses `ion-focusable`. Do not use this if focusing the element as a result of a keyboard event as the focus utility should handle this for us. This method should be used when we want to programmatically focus an element as a result of another user action. (Ex: We focus the first element inside of a popover when the user presents it, but the popover is not always presented as a result of keyboard action.)
336+
* Sets focus on elements that use `ion-focusable`.
337+
* @param elements - The elements to set focus on.
337338
*/
338339
"setFocus": (elements: HTMLElement[]) => Promise<void>;
339340
/**

core/src/components/app/app.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ export class App implements ComponentInterface {
1717
@Element() el!: HTMLElement;
1818

1919
/**
20-
* Used to set focus on an element that uses `ion-focusable`.
21-
* Do not use this if focusing the element as a result of a keyboard
22-
* event as the focus utility should handle this for us. This method
23-
* should be used when we want to programmatically focus an element as
24-
* a result of another user action. (Ex: We focus the first element
25-
* inside of a popover when the user presents it, but the popover is not always
26-
* presented as a result of keyboard action.)
20+
* Sets focus on elements that use `ion-focusable`.
21+
*
22+
* @param elements - The elements to set focus on.
2723
*/
2824
@Method()
2925
async setFocus(elements: HTMLElement[]) {
26+
/**
27+
* The focus-visible utility is used to set focus on an
28+
* element that uses `ion-focusable`.
29+
*/
3030
focusElements(elements);
3131
}
3232

core/src/utils/focus-visible.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export const getOrInitFocusVisibleUtility = () => {
3838
* a result of another user action. (Ex: We focus the first element
3939
* inside of a popover when the user presents it, but the popover is not always
4040
* presented as a result of keyboard action.)
41+
*
42+
* @param elements - The elements to set focus on.
4143
*/
4244
export const focusElements = (elements: Element[]) => {
4345
const focusVisible = getOrInitFocusVisibleUtility();

core/src/utils/helpers.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,17 @@ export const hasShadowDom = (el: HTMLElement) => {
256256
return !!el.shadowRoot && !!(el as any).attachShadow;
257257
};
258258

259+
/**
260+
* Focuses a given element while ensuring proper focus management
261+
* within the Ionic framework. If the element is marked as `ion-focusable`,
262+
* this function will delegate focus handling to `ion-app` or manually
263+
* apply focus when a custom app root is used.
264+
*
265+
* This function helps maintain accessibility and expected focus behavior
266+
* in both standard and custom root environments.
267+
*
268+
* @param el - The element to focus.
269+
*/
259270
export const focusVisibleElement = (el: HTMLElement) => {
260271
el.focus();
261272

@@ -281,15 +292,21 @@ export const focusVisibleElement = (el: HTMLElement) => {
281292
app.setFocus([el]);
282293
} else {
283294
/**
284-
* If the user has provided a custom app root selector,
285-
* then we need to manually set focus on the element
286-
* since the focus-visible utility will not be available
287-
* on the custom app root.
288-
*
289-
* The focus-visible utility is used to set focus on an
290-
* element that uses `ion-focusable`.
295+
* When using a custom app root selector, the focus-visible
296+
* utility is not available to manage focus automatically.
297+
* If we set focus immediately, the element may not be fully
298+
* rendered or interactive, especially if it was just added
299+
* to the DOM. Using requestAnimationFrame ensures that focus
300+
* is applied on the next frame, allowing the DOM to settle
301+
* before changing focus.
291302
*/
292-
focusElements([el]);
303+
requestAnimationFrame(() => {
304+
/**
305+
* The focus-visible utility is used to set focus on an
306+
* element that uses `ion-focusable`.
307+
*/
308+
focusElements([el]);
309+
});
293310
}
294311
}
295312
}

0 commit comments

Comments
 (0)