Live demo: combobox-demo.html (BEFORE/AFTER)
Minimum viable pattern
- Input keeps focus; highlighted option tracked with
aria-activedescendant. - Input:
role="combobox",aria-autocomplete="list",aria-controls,aria-expanded. - Popup:
role="listbox". Items:role="option"with stable IDs. - Keyboard:
↓/↑to move,Enterto select,Escto close. - Pointer: click an option selects it without stealing focus (prevent default on mousedown).
Pitfalls (what breaks real users)
- Focus theft: moving focus into the popup makes it easy to lose your place. Prefer keeping focus in the input.
- Live-region spam: announcing every keystroke is exhausting. Announce “N suggestions” and selection results instead.
- Missing state: keep
aria-expandedaccurate when the popup opens/closes. - Inconsistent click: if click steals focus, selection can fail on blur. Prevent mousedown default.
Good defaults
- Limit suggestions (e.g., top 6) so announcements are short.
- Make the highlight visible (outline, not only color).
- Provide one short instruction sentence via
aria-describedby.