diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 5f4b125714..afdaf6a79d 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 293f1d1d26..fb2b190020 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -181,6 +181,30 @@ 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. That approach + * would be less maintainable and more error-prone. + */ + 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; + } + el.setAttribute(SKIP_SCROLL_ASSIST, 'true'); el.focus(); };