UX Design

Accessible Search and Autocomplete Design: ARIA Combobox Patterns

By EZUD Published · Updated

Accessible Search and Autocomplete Design: ARIA Combobox Patterns

Search with autocomplete — type a few characters, see suggestions, select one — is one of the most complex interactive patterns to make accessible. It combines text input, dynamic content updates, keyboard navigation, and screen reader announcements into a single interaction. The W3C WAI-ARIA combobox pattern provides the specification, but the implementation details determine whether your search actually works for everyone.

The ARIA Combobox Pattern

A combobox is an input that provides suggestions via a popup listbox. The W3C ARIA 1.2 combobox pattern defines the structure:

<label for="city-search">Search cities</label>
<div class="combobox-wrapper">
  <input
    id="city-search"
    type="text"
    role="combobox"
    aria-expanded="false"
    aria-autocomplete="list"
    aria-controls="city-listbox"
    aria-activedescendant=""
  />
  <ul id="city-listbox" role="listbox" hidden>
    <li role="option" id="opt-1">Austin, TX</li>
    <li role="option" id="opt-2">Atlanta, GA</li>
    <li role="option" id="opt-3">Albuquerque, NM</li>
  </ul>
</div>

Key Attributes

  • role="combobox" on the input identifies it as a combobox to screen readers
  • aria-expanded communicates whether the suggestion list is currently visible
  • aria-autocomplete="list" tells screen readers that suggestions will appear as the user types
  • aria-controls connects the input to its suggestion listbox
  • aria-activedescendant points to the currently highlighted option, allowing focus to remain in the input while visually indicating selection in the list

Keyboard Interaction Model

The keyboard interaction is where combobox implementations most frequently fail:

When the Listbox Is Closed

  • Down Arrow: Opens the listbox and highlights the first option
  • Alt + Down Arrow: Opens the listbox without moving highlight (some implementations)
  • Character input: Opens the listbox with filtered suggestions

When the Listbox Is Open

  • Down Arrow: Moves highlight to the next option
  • Up Arrow: Moves highlight to the previous option
  • Enter: Selects the highlighted option and closes the listbox
  • Escape: Closes the listbox without selecting, clears the input (or reverts to pre-open value)
  • Home / End: Moves cursor within the input text (not the listbox)
  • Tab: Selects the highlighted option (if any) and moves focus to the next form element

Critical: Focus Stays in the Input

Unlike dropdown menus where focus moves into the list, combobox focus remains in the text input at all times. The aria-activedescendant attribute indicates which list item is highlighted without moving DOM focus. This allows users to continue typing while navigating suggestions — a fundamental expectation of search interactions.

Announcing Suggestions to Screen Readers

When suggestions appear or update, screen reader users need to know without losing their place. The W3C pattern recommends using a live region to announce the count of results:

<div aria-live="polite" aria-atomic="true" class="visually-hidden">
  3 suggestions available
</div>

Update this text whenever the suggestion list changes. Announcing the count — rather than reading every suggestion — prevents information overload while confirming that the system is responding to input.

When the user arrows through suggestions, aria-activedescendant causes the screen reader to announce each option as it is highlighted. The user hears both the option text and its position (“Austin, TX, 1 of 3”).

Design Considerations

Minimum Character Threshold

Showing suggestions after a single character may produce too many results. A common pattern is to require 2-3 characters before displaying suggestions. Communicate this threshold to users:

<p id="search-hint" class="visually-hidden">Type at least 2 characters for suggestions</p>
<input aria-describedby="search-hint" ... />

Debouncing

Network requests for suggestions should be debounced (typically 200-300ms) to avoid excessive API calls and flickering result lists. The debounce delay should not be so long that users perceive the interface as unresponsive.

No Results State

When the search returns no matches, communicate this clearly:

<ul id="city-listbox" role="listbox">
  <li role="option" aria-disabled="true">No results found</li>
</ul>

The live region should also announce “No suggestions available” so screen reader users do not assume the component is broken.

Loading State

If suggestions require an API call, announce the loading state through the live region: “Loading suggestions…” followed by the result count when they arrive.

Grouping Suggestions

For search interfaces that group results by category (Products, Articles, People), use role="group" with aria-label within the listbox:

<ul role="listbox">
  <li role="group" aria-label="Products">
    <ul>
      <li role="option" id="prod-1">Widget Pro</li>
      <li role="option" id="prod-2">Widget Lite</li>
    </ul>
  </li>
  <li role="group" aria-label="Articles">
    <ul>
      <li role="option" id="art-1">Getting Started with Widgets</li>
    </ul>
  </li>
</ul>

Screen readers will announce the group name before reading options within it.

Common Mistakes

  1. Moving DOM focus to the listbox: Focus must stay in the input. Use aria-activedescendant to indicate the active option.

  2. Using role="menu" instead of role="listbox": Menus are for action items; listboxes are for selection. Search suggestions are selections.

  3. Missing aria-expanded state management: The attribute must toggle between “true” and “false” as the listbox opens and closes. Missing this leaves screen reader users unaware of the listbox state.

  4. Not updating aria-activedescendant: When the user arrows through options, aria-activedescendant on the input must point to the currently highlighted option’s id. Without this, screen readers do not announce the highlighted option.

  5. Inaccessible suggestion formatting: If suggestions include images, secondary text, or icons, ensure the accessible name for each role="option" conveys the full meaning. Use aria-label if the visual presentation uses elements that screen readers would read in a confusing order.

Mobile Considerations

On mobile devices, native autocomplete behaviors vary by platform. Custom combobox implementations must work with virtual keyboards and touch input:

  • Ensure the listbox does not get obscured by the virtual keyboard
  • Touch targets for suggestions should be at least 44x44 CSS pixels
  • Consider using inputmode="search" to trigger a search-optimized keyboard layout

Testing

  • NVDA + Chrome: Type characters, verify suggestion count is announced. Arrow through options, verify each is read. Press Enter, verify selection is populated in the input.
  • VoiceOver + Safari: Test on both macOS and iOS. Touch interaction on iOS requires special attention — double-tap to select options.
  • JAWS + Edge: Verify aria-activedescendant announcements work. JAWS has historically had inconsistencies with this attribute.
  • Keyboard only: Complete a search using only keyboard. Navigate suggestions, select, and verify the result. Use comprehensive testing methodology for thorough coverage.

Key Takeaways

Accessible search autocomplete requires the ARIA combobox pattern with careful attention to aria-activedescendant, aria-expanded, and live region announcements. Focus must remain in the input while arrow keys navigate the suggestion list. Announce result counts politely, handle no-results and loading states explicitly, and test with multiple screen reader and browser combinations. The pattern is complex, but when implemented correctly, it provides an efficient search experience for every user.

Sources