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.
<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>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 criterion | Level | What it requires here |
|---|---|---|
| 4.1.2 Name, Role, Value | A | The 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 Instructions | A | The 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 Keyboard | A | Every 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 Messages | AA | Result 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 Input | A | Typing 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 Visible | AA | The 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 Relationships | A | The 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 Labels | AA | The label says what can be searched so the user knows what kind of text to enter. |
Expected Keyboard Interaction
| Key | Expected result |
|---|---|
| Typing | Filters the options and opens the popup when there is a query; the count is announced. |
| Down arrow | Highlights the next option and wraps from the last to the first. The caret does not move because the default is prevented. |
| Up arrow | Highlights the previous option and wraps from the first to the last. |
| Enter | Chooses the highlighted option: the input takes its value, the popup closes, and the selection is announced. |
| Escape | Closes the popup and clears the highlight; the typed text is kept. |
| Tab | Leaves the field for the next control; the popup closes without changing the value. |
The Failures We See Most Often
- 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.
- 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.
- 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.