Skip to content

AutocompleteInput can point aria-activedescendant at a nonexistent option #416

Description

@czarandy

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:

  1. 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a11yAccessibilitybugSomething isn't workingsmallApproximately small amount of work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions