Problem
The aria-activedescendant guard only checks highlightedIndex >= 0 (src/components/AutocompleteInput/BaseAutocompleteInput.tsx:430-434) — never whether that index is within the rendered results.
Two concrete dangling windows:
- With results shown and
highlightedIndex = 2, typing another character enters the loading state — runSearch flips setIsLoading(true) without resetting highlightedIndex (BaseAutocompleteInput.tsx:244-251; it's only reset after the await at :262,271). The loading/empty/error branches render no role="option" elements (:373-392), yet the input still advertises aria-activedescendant="…-option-2" pointing at nothing.
selectItem clears setResults([]) without touching highlightedIndex (:323-343); in the reopen-on-select branch (:339-341) the menu stays open and re-bootstraps, so the stale index survives the whole async gap.
Screen readers either announce nothing or report a broken reference during these windows.
Expected
aria-activedescendant is only present when it references a currently rendered option.
Suggested fix
Also require highlightedIndex < results.length (and that options are actually rendered — not loading/empty/error) before emitting the attribute, and/or reset highlightedIndex when entering loading state or clearing results. Add tests for the loading transition and select-then-reopen flow.
Problem
The
aria-activedescendantguard only checkshighlightedIndex >= 0(src/components/AutocompleteInput/BaseAutocompleteInput.tsx:430-434) — never whether that index is within the rendered results.Two concrete dangling windows:
highlightedIndex = 2, typing another character enters the loading state —runSearchflipssetIsLoading(true)without resettinghighlightedIndex(BaseAutocompleteInput.tsx:244-251; it's only reset after the await at:262,271). The loading/empty/error branches render norole="option"elements (:373-392), yet the input still advertisesaria-activedescendant="…-option-2"pointing at nothing.selectItemclearssetResults([])without touchinghighlightedIndex(:323-343); in the reopen-on-select branch (:339-341) the menu stays open and re-bootstraps, so the stale index survives the whole async gap.Screen readers either announce nothing or report a broken reference during these windows.
Expected
aria-activedescendantis only present when it references a currently rendered option.Suggested fix
Also require
highlightedIndex < results.length(and that options are actually rendered — not loading/empty/error) before emitting the attribute, and/or resethighlightedIndexwhen entering loading state or clearing results. Add tests for the loading transition and select-then-reopen flow.