Back to Learn Hub
Comprehensive Guide

Search & Autocomplete

Combobox patterns, keyboard navigation, and result announcements

Combobox Pattern

Search with autocomplete uses the combobox pattern: an input combined with a popup listbox of suggestions. The key roles are combobox, listbox, and option.

role='combobox'

The input element gets role="combobox" (or use native input with aria-autocomplete="list").

aria-expanded

Set to "true" when suggestions popup is visible, "false" when hidden.

aria-activedescendant

Points to the ID of the currently highlighted option, so screen readers track focus.

Interactive Demo

Type to search ARIA attributes. Use arrow keys to navigate, Enter to select, Escape to close.

Combobox Structure
<div>
  <!-- Live region for announcements -->
  <div role="status" aria-live="polite" className="sr-only">
    {announcement}
  </div>

  <!-- Input with combobox role -->
  <input
    type="text"
    role="combobox"
    aria-expanded={isOpen}
    aria-controls="search-listbox"
    aria-activedescendant={activeId}
    aria-autocomplete="list"
    aria-label="Search"
  />

  <!-- Listbox popup -->
  {isOpen && (
    <ul id="search-listbox" role="listbox" aria-label="Search results">
      <li id="option-1" role="option" aria-selected={activeIndex === 0}>
        Result 1
      </li>
      <li id="option-2" role="option" aria-selected={activeIndex === 1}>
        Result 2
      </li>
    </ul>
  )}
</div>
aria-activedescendant vs Focus
Virtual focus (aria-activedescendant) keeps real focus on the input so users can keep typing while browsing results. The highlighted option is communicated visually and to screen readers, but keyboard focus stays in the input.

Understanding the Search and Autocomplete Pattern

A search box that offers suggestions as you type is a combobox: a text input combined with a popup list of options that filters on every keystroke. The WAI-ARIA combobox pattern defines the roles and states that make the relationship between the two parts explicit. The demo above uses the list-autocomplete variant, where the popup is a listbox, the options are not editable, and keyboard focus stays in the input the whole time so the user can keep typing while they browse.

That last point is the heart of the pattern. Instead of moving focus into the list, the input carries aria-activedescendant, which names the option that is currently highlighted. The screen reader announces the highlighted option while the caret, and real focus, never leave the text field. The input also reports whether the popup is open with aria-expanded and points at it with aria-controls, and a polite live region announces how many results are available, or that there are none, because nothing else would tell a screen reader user that the list had appeared.

WCAG 2.2 Success Criteria Involved

Success criterionLevelWhat it requires here
4.1.2 Name, Role, ValueAThe input has role combobox with aria-expanded, aria-controls, and aria-activedescendant; the popup is a listbox of options with aria-selected on the highlighted one.
3.3.2 Labels or InstructionsAThe field has a label. Placeholder text is not a label; it disappears when the user types and is often too faint to read.
2.1.1 KeyboardAEvery option can be reached and chosen with the keyboard; a mouse-only click handler on the list items is a failure.
4.1.3 Status MessagesAAResult counts, 'no results', and 'loading' are announced through a live region because focus stays in the input and does not reach the list.
3.2.2 On InputATyping must not submit the form or navigate away on its own; choosing a suggestion fills the field and leaves the user in control.
2.4.7 Focus VisibleAAThe input shows a focus indicator, and the highlighted option is visually distinct from the others in a way that is not colour alone.
1.3.1 Info and RelationshipsAThe option list is a real list with listbox and option semantics, not a set of divs styled to look like one.
2.4.6 Headings and LabelsAAThe label says what can be searched so the user knows what kind of text to enter.

Expected Keyboard Interaction

Keyboard interaction for the search combobox demo
KeyExpected result
TypingFilters the options and opens the popup when there is a query; the count is announced.
Down arrowHighlights the next option and wraps from the last to the first. The caret does not move because the default is prevented.
Up arrowHighlights the previous option and wraps from the first to the last.
EnterChooses the highlighted option: the input takes its value, the popup closes, and the selection is announced.
EscapeCloses the popup and clears the highlight; the typed text is kept.
TabLeaves the field for the next control; the popup closes without changing the value.

The Failures We See Most Often

  1. Missing state attributes. The input is a plain text field with a list drawn beneath it. Without aria-expanded, aria-controls, and aria-activedescendant a screen reader hears 'edit text' and nothing about the suggestions.
  2. Results that are never announced. Sighted users see the list appear. Screen reader users hear nothing, keep typing, and never learn there were matches, or that there were none.
  3. Arrow keys that fight the input. Either real focus is moved into the list so typing stops working, or the arrow key default is not prevented and the caret jumps to the start or end of the text while the highlight moves.

The accessible combobox guide covers the other variants of the pattern, including editable comboboxes and select-only ones, the difference between aria-activedescendant and moving focus, debouncing and loading states, and how the native <datalist> compares.