From 06dd32157f2f1a26e85c61722de93a0ad52958a1 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 13 May 2025 16:37:40 -0700 Subject: [PATCH 1/4] fix(scroll-assist): allow focus on input's siblings --- core/src/components/input/input.tsx | 9 --------- .../utils/input-shims/hacks/scroll-assist.ts | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 5f4b1257141..afdaf6a79d2 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -868,15 +868,6 @@ export class Input implements ComponentInterface { */ ev.preventDefault(); }} - onFocusin={(ev) => { - /** - * Prevent the focusin event from bubbling otherwise it will cause the focusin - * event listener in scroll assist to fire. When this fires, focus will be moved - * back to the input even if the clear button was never tapped. This poses issues - * for screen readers as it means users would be unable to swipe past the clear button. - */ - ev.stopPropagation(); - }} onClick={this.clearTextInput} > diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index 293f1d1d26d..319e37f2a40 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -181,6 +181,24 @@ const setManualFocus = (el: HTMLElement) => { return; } + /** + * Optimization for scenarios where the currently focused element is a sibling + * of the target element. In such cases, we avoid setting `SKIP_SCROLL_ASSIST`. + * + * This is crucial for accessibility: input elements can now contain focusable + * siblings (e.g., clear buttons, slotted elements). If we didn't skip setting + * the attribute here, screen readers would be unable to navigate to and interact + * with these sibling elements. + * + * Without this check, we would need to call `ev.stopPropagation()` on the + * 'focusin' event of each focusable sibling to prevent the scroll assist + * listener from incorrectly moving focus back to the input. This approach + * is less maintainable and more error-prone. + */ + if (document.activeElement?.parentNode === el.parentNode) { + return; + } + el.setAttribute(SKIP_SCROLL_ASSIST, 'true'); el.focus(); }; From e468923d06d9c1852bd4f8a01c8c57d798801a9b Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 13 May 2025 17:01:45 -0700 Subject: [PATCH 2/4] chore(scroll-assist): run lint --- core/src/utils/input-shims/hacks/scroll-assist.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index 319e37f2a40..399c604f9cd 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -190,7 +190,7 @@ const setManualFocus = (el: HTMLElement) => { * the attribute here, screen readers would be unable to navigate to and interact * with these sibling elements. * - * Without this check, we would need to call `ev.stopPropagation()` on the + * Without this check, we would need to call `ev.stopPropagation()` on the * 'focusin' event of each focusable sibling to prevent the scroll assist * listener from incorrectly moving focus back to the input. This approach * is less maintainable and more error-prone. From c49abb9e45efb7ccdaf586d8662f8b493ff0572d Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 15 May 2025 12:59:30 -0700 Subject: [PATCH 3/4] Update core/src/utils/input-shims/hacks/scroll-assist.ts Co-authored-by: Shane --- core/src/utils/input-shims/hacks/scroll-assist.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index 399c604f9cd..0f0729f6a21 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -192,8 +192,8 @@ const setManualFocus = (el: HTMLElement) => { * * Without this check, we would need to call `ev.stopPropagation()` on the * 'focusin' event of each focusable sibling to prevent the scroll assist - * listener from incorrectly moving focus back to the input. This approach - * is less maintainable and more error-prone. + * listener from incorrectly moving focus back to the input. That approach + * would be less maintainable and more error-prone. */ if (document.activeElement?.parentNode === el.parentNode) { return; From 0f30f6254e5ad4ad8d33be576b7feb3f8084034b Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 22 May 2025 11:53:53 -0700 Subject: [PATCH 4/4] fix(scroll-assist): check for label instead --- core/src/utils/input-shims/hacks/scroll-assist.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index 0f0729f6a21..fb2b1900202 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -195,7 +195,13 @@ const setManualFocus = (el: HTMLElement) => { * listener from incorrectly moving focus back to the input. That approach * would be less maintainable and more error-prone. */ - if (document.activeElement?.parentNode === el.parentNode) { + const inputId = el.getAttribute('id'); + const label = el.closest(`label[for="${inputId}"]`); + const activeElLabel = document.activeElement?.closest(`label[for="${inputId}"]`); + + if (label !== null && label === activeElLabel) { + // If the label is the same as the active element label, then + // we don't need to set the `SKIP_SCROLL_ASSIST` and reset focus. return; }