Skip to Content
Component ExamplesCombobox & Autocomplete

Overview

The combobox is one of the most complex ARIA patterns. It combines a text input with a popup listbox, allowing users to type to filter options and select from the results. The most common mistake is building a custom dropdown with no ARIA roles, no keyboard navigation, and no live announcements — leaving screen reader and keyboard users unable to operate the widget.

WCAG Criteria:

Key requirements:

  • DOM focus stays on the input — aria-activedescendant provides virtual focus in the popup
  • The input needs role="combobox", aria-autocomplete="list", aria-expanded, and aria-controls
  • The popup list needs role="listbox" with role="option" children
  • Must handle: Arrow Down/Up to move through options, Enter to select, Escape to close
  • Always announce result count changes via an aria-live="polite" region
  • Browser does not auto-scroll aria-activedescendant targets — JS must call scrollIntoView

Autocomplete Combobox

Accessible Autocomplete vs. Unsemantic Dropdown

Inaccessible
<!-- No ARIA roles, no keyboard nav, no live announcements --> <label>Choose a fruit</label> <input type="text" placeholder="Type to search..." onclick="showDropdown()" oninput="filterItems(this.value)"> <div class="dropdown-list"> <div onclick="selectItem('Apple')">Apple</div> <div onclick="selectItem('Banana')">Banana</div> <div onclick="selectItem('Cherry')">Cherry</div> <div onclick="selectItem('Date')">Date</div> </div>
Live Preview
Accessible
<label id="fruit-label" for="fruit-input">Choose a fruit</label> <input id="fruit-input" type="text" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="fruit-listbox" aria-activedescendant="" aria-labelledby="fruit-label" autocomplete="off"> <ul id="fruit-listbox" role="listbox" aria-label="Fruits" hidden> <li role="option" id="opt-apple">Apple</li> <li role="option" id="opt-banana">Banana</li> <li role="option" id="opt-cherry">Cherry</li> <li role="option" id="opt-date">Date</li> <li role="option" id="opt-elderberry">Elderberry</li> </ul> <span role="status" aria-live="polite" class="sr-only"> 5 results available </span> <script> // On input: filter options, update aria-expanded // Arrow Down/Up: move aria-activedescendant, scrollIntoView // Enter: select current option, close listbox // Escape: close listbox // On filter change: update aria-live status text </script>
Live Preview

What’s wrong with the unsemantic dropdown?

  • The input has no role="combobox" — screen readers don’t identify it as a searchable dropdown
  • The dropdown <div> items have no role="option" — they are invisible to assistive technology
  • No aria-expanded means the user can’t tell if the list is open or closed
  • No aria-activedescendant means there is no virtual focus indicator for screen readers
  • Arrow keys don’t work — keyboard-only users cannot navigate the options
  • No live region announces how many results are available after filtering

What the screen reader announces:

VersionAnnouncement
Inaccessible (plain input)“Choose a fruit, edit text” — no combobox context, no options announced
Accessible (combobox)“Choose a fruit, combobox, collapsed, edit text”
When expanded”Choose a fruit, combobox, expanded, edit text”
Navigating options”Apple, 1 of 5” (via aria-activedescendant)
After filtering”3 results available” (via aria-live region)

Resources