Engrain by ByteRush

QLT.04.02 Senior· 12 minCore — asked often

Menus, listbox and combobox: accessible autocomplete

Build an accessible autocomplete with the combobox pattern: an input that controls a listbox, aria-activedescendant for the highlighted option, aria-autocomplete and aria-expanded, typeahead, and why role=menu is wrong for site navigation.

Comes up in: Web fundamentals, Machine coding, Frontend system design

Learn#

Farhan’s city picker shows suggestions as you type, but keyboard users cannot reach them, and screen readers say nothing when the list opens. It is a div list under an input.

A combobox is an input that controls a popup of suggestions, usually a listbox of options. Focus stays in the input while the user moves through options; aria-activedescendant tells assistive technology which option is highlighted:

<label for="city">City</label>
<input id="city" role="combobox" aria-autocomplete="list" aria-expanded="true"
       aria-controls="city-list" aria-activedescendant="city-opt-0">
<ul id="city-list" role="listbox" aria-label="Cities">
  <li id="city-opt-0" role="option" aria-selected="true">Bangalore</li>
  <li id="city-opt-1" role="option" aria-selected="false">Banda</li>
</ul>

The active descendant is the option that is highlighted while focus stays elsewhere. Enter selects it, Escape closes the list, and typing keeps working at all times.

Choosing a city with only the keyboardStep 1 of 4

Page

  • input[aria-expanded=true]
  • listbox: Bangalore, Banda, Banswara

State

    empty

    Console

      empty

      The user types "ban" in the city field. The listbox opens with Bangalore, Banda and Banswara; aria-expanded becomes true.

      Read the steps as text
      1. The user types "ban" in the city field. The listbox opens with Bangalore, Banda and Banswara; aria-expanded becomes true.
      2. Down Arrow highlights Bangalore. Focus stays in the input; aria-activedescendant points at the option's id.
      3. The screen reader announces "Bangalore, 1 of 3". The user can still type, because focus never left the input.
      4. Enter selects Bangalore, fills the input and closes the list. Escape would have closed it without selecting.

      Predict#

      Predict first

      A site's main navigation uses role="menu" and role="menuitem". What is wrong?

      Interview angle#

      Say it like this — about 30 seconds

      “An accessible autocomplete uses the combobox pattern. The input has role combobox, aria-expanded, aria-controls pointing at a listbox, and aria-autocomplete list. Options have role option and unique ids. Focus stays in the input; arrow keys move a highlighted option, and aria-activedescendant points at its id so screen readers announce it. Enter selects, Escape closes, and a live region can announce the number of results. I do not use role menu for this or for site navigation.”

      Stays on your device. Nothing is uploaded.
      Follow-up How do you build an accessible autocomplete or combobox?
      Input role=combobox with aria-expanded, aria-controls and aria-activedescendant; listbox with options; arrows, Enter and Escape; results count announced politely.
      Follow-up Why aria-activedescendant instead of moving focus to the option?
      Focus stays in the input, so typing continues to work and the caret does not jump.
      Follow-up What is typeahead in a listbox?
      Typing a letter moves to the next option starting with it, as in a native select.

      Practice#

      On your own

      Write the state machine behind an accessible autocomplete, and the aria-activedescendant value it produces.

      Done when

      • Typing opens the list when there are options; arrows move and wrap.
      • Enter selects the active option and closes; Escape closes without selecting.
      • activeDescendant returns the right id, or "" when closed or nothing is active.
      Your solution
      Ctrl/⌘ + Enter

      Remember#

      Try to answer each card before you open it. Then add them to your reviews.

      Which attribute points at the highlighted option while focus stays in the input?

      aria-activedescendant.

      What role does the suggestion popup usually have?

      listbox, with option children.

      Should site navigation use role="menu"?

      No. Use nav with links; menu is for app command menus.

      What do Enter and Escape do in a combobox?

      Enter selects the active option; Escape closes the list.

      Go deeper

      Four layers. Stop at the one your interview needs; each ends with a quick check.

      The core ideaEvery round

      aria-autocomplete="list" says suggestions appear in a popup; "both" also completes text inline. Keep aria-expanded in sync with the popup.

      Check yourself: What does aria-autocomplete=&quot;list&quot; mean?

      The input shows a list of suggestions.

      How it works underneathSenior rounds

      Option ids must be unique on the page, since aria-activedescendant references them. Mark the highlighted option with aria-selected="true" and keep it scrolled into view Source: WAI-ARIA APG: Combobox pattern.

      Check yourself: Why must each option have a unique id?

      aria-activedescendant refers to the option by id.

      Edge cases and trapsWhere people slip

      Typeahead lets users jump by typing the first letters, in listboxes without an input.
      Announce result counts with a polite live region (QLT.04.03), and debounce it, so each keystroke does not trigger speech.

      Check yourself: How do you announce how many results appeared?

      A polite live region, such as &quot;5 results available&quot;.

      In productionStaff-level answers

      Use role="menu" only for app-style command menus Source: WAI-ARIA APG: Menu and menubar pattern. For short fixed lists, a native <select> beats any custom widget.
      This pattern feeds the autocomplete machine-coding task (MC.03.01).

      Check yourself: When should you use a native select instead?

      When there is a short, fixed list of options and no filtering.

      Finished the five steps? Mark it, and its cards join your reviews.

      Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

      Interview questions this answers

      • How do you build an accessible autocomplete/combobox?