Combobox — accessibility

Keyboard

  • Tab focuses the input; focusing opens the list when suggestions exist (onFocus → open).
  • Typing opens the list and highlights the first suggestion; ArrowDown opens and moves the highlight down, ArrowUp moves it up (clamped, no wrap); Enter picks the highlighted suggestion when the list is shown; Esc closes the list and keeps the text.
  • Mouse: hovering a row moves the highlight (onMouseEnter); rows use onMouseDown preventDefault so the input keeps focus on click.
  • Click outside the field and outside the portalled list closes it (capture-phase mousedown).
  • No Home/End, no Tab trapping, no shortcut chip.

ARIA

  • Input: role="combobox", aria-expanded (true while the list shows), aria-autocomplete="list", aria-label from ariaLabel — pass it whenever the field is not inside <Field>.
  • List: ul[role="listbox"]; rows li[role="option"] with aria-selected on the highlighted row.
  • No aria-controls / aria-owns from the input to the portalled list and no aria-activedescendant — the highlighted row is not announced by screen readers (limit).
  • The empty row li.acrm-combobox-empty has no role; it is read as list content.

Focus

  • The input sets outline: none; the visible indicator is the wrapper .acrm-combobox.is-open accent border + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent).
  • .is-open is applied only while suggestions or the empty text show — a focused combobox with an empty query (or emptyText unset) has NO visible focus ring (limit).
  • Focus never leaves the input: the list is mouse/arrow driven, so closing needs no focus restore.

Contrast

Computed from packages/ui/src/tokens/tokens.css:

  • Input text --fg = --ink-900 on --surface-100 = 17.59:1 (light), 14.53:1 (dark).
  • Placeholder --fg-muted on white = 2.85:1 (light), 3.63:1 (dark) — below AA.
  • Leading icon --fg-secondary #7d8184 on white = 3.93:1 (light); #9a9ca1 on #1b1c1f = 6.2:1 (dark) — non-text, passes 3:1.
  • Row .nm --fg on the list surface = 17.59:1 / 14.53:1; on .is-active --hover-surface = 17.0:1 (light) / 13.09:1 (dark).
  • .psc and empty text --fg-muted at 12–13px = 2.85:1 (light) / 3.63:1 (dark) — below AA 4.5:1.
  • Field border --border-strong = 1.38:1 (light) / 1.55:1 (dark); open border --accent = 4.44:1 / 3.83:1.

Known limits

  • No aria-activedescendant, aria-controls or live announcement of the highlighted suggestion.
  • No focus ring while the list is closed (input outline: none, wrapper ring tied to .is-open).
  • Placeholder, .psc and empty text (--fg-muted) are below AA 4.5:1 in light theme.
  • ArrowUp on the first row does not close the list or return to the text; Esc is the only close key.
  • The list is not a tab stop: keyboard users pick only with arrows + Enter.

Source: docs/select/combobox.a11y.md · GitLab