Skip to content

Commit 2dea607

Browse files
thetaPCShaneK
andauthored
fix(scroll-assist): allow focus on input's siblings (#30409)
Co-authored-by: Shane <[email protected]>
1 parent b740070 commit 2dea607

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

core/src/components/input/input.tsx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -868,15 +868,6 @@ export class Input implements ComponentInterface {
868868
*/
869869
ev.preventDefault();
870870
}}
871-
onFocusin={(ev) => {
872-
/**
873-
* Prevent the focusin event from bubbling otherwise it will cause the focusin
874-
* event listener in scroll assist to fire. When this fires, focus will be moved
875-
* back to the input even if the clear button was never tapped. This poses issues
876-
* for screen readers as it means users would be unable to swipe past the clear button.
877-
*/
878-
ev.stopPropagation();
879-
}}
880871
onClick={this.clearTextInput}
881872
>
882873
<ion-icon aria-hidden="true" icon={clearIconData}></ion-icon>

core/src/utils/input-shims/hacks/scroll-assist.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,30 @@ const setManualFocus = (el: HTMLElement) => {
181181
return;
182182
}
183183

184+
/**
185+
* Optimization for scenarios where the currently focused element is a sibling
186+
* of the target element. In such cases, we avoid setting `SKIP_SCROLL_ASSIST`.
187+
*
188+
* This is crucial for accessibility: input elements can now contain focusable
189+
* siblings (e.g., clear buttons, slotted elements). If we didn't skip setting
190+
* the attribute here, screen readers would be unable to navigate to and interact
191+
* with these sibling elements.
192+
*
193+
* Without this check, we would need to call `ev.stopPropagation()` on the
194+
* 'focusin' event of each focusable sibling to prevent the scroll assist
195+
* listener from incorrectly moving focus back to the input. That approach
196+
* would be less maintainable and more error-prone.
197+
*/
198+
const inputId = el.getAttribute('id');
199+
const label = el.closest(`label[for="${inputId}"]`);
200+
const activeElLabel = document.activeElement?.closest(`label[for="${inputId}"]`);
201+
202+
if (label !== null && label === activeElLabel) {
203+
// If the label is the same as the active element label, then
204+
// we don't need to set the `SKIP_SCROLL_ASSIST` and reset focus.
205+
return;
206+
}
207+
184208
el.setAttribute(SKIP_SCROLL_ASSIST, 'true');
185209
el.focus();
186210
};

0 commit comments

Comments
 (0)