Skip to content

Combobox and autocomplete

Preview Available in release assets

Enhance a native text field with bounded ARIA listbox navigation while keeping typed values, submission, and server-provided results durable.

Combobox and autocomplete primary example

Show code
<form action="/locations" method="get">
  <div class="thin-combobox" data-enhance="combobox">
    <label for="location">Location</label>
    <input class="thin-input" id="location" name="location" role="combobox" autocomplete="off" aria-expanded="false" aria-controls="location-results" aria-describedby="location-status" />
    <ul class="thin-combobox-listbox" id="location-results" role="listbox">
      <li id="location-chi" role="option" data-value="Chicago, Illinois">Chicago, Illinois</li>
      <li id="location-chihuahua" role="option" data-value="Chihuahua, Mexico">Chihuahua, Mexico — a deliberately long result label that wraps</li>
    </ul>
    <small class="thin-combobox-status" id="location-status">2 server-provided suggestions. Type any location or choose a suggestion.</small>
  </div>
  <button class="thin-button">Search</button>
</form>

Each authored example uses the production assets and includes copyable markup.

Anatomy

  • Explicit label
  • Native named text input with role=combobox
  • Server-authored listbox
  • Options with durable values
  • Status or error text
  • Submit button

Variants and sizes

  • Free text with suggestions — shown above
  • Server-filtered autocomplete — shown above

Rendered fixtures exercise authored content and constrained layouts with the same production assets.

  • Closed — shown above
  • Open — shown above
  • Active option — shown above
  • No results — shown above
  • Server error — shown above
  • Long option — shown above
  • Disabled option — shown above
  • Narrow container — shown above
  • Reconnected after morph — shown above

Interaction and keyboard behavior

Typing remains native. Down/Up opens and moves the active descendant; Home/End move to bounds; Enter copies the active option into the input; Escape closes. Focus remains on the input, pointer selection is supported, and ordinary form submission remains canonical.

Accessibility

Use the ARIA combobox/listbox/option relationship, keep DOM focus on the input, expose aria-expanded and aria-activedescendant, and provide persistent result or error text. Do not announce on every keystroke unnecessarily. Results must be authored by the server or application; this element owns only mechanical selection.

Contract
COMBO · APG pattern
Basis
APG Combobox with a flat listbox popup; current implementation uses aria-activedescendant
Behavior guarantees
  • Keeps DOM focus on the named native input and uses aria-activedescendant for a flat list of direct-child options.
  • Generates missing listbox and option IDs, ignores nested options, and skips native and ARIA-disabled options.
  • Refreshes after child-list morphs.
Evidence
  • tests/unit/behaviors/combobox.test.ts
  • tests/unit/library/advanced-component-contracts.test.ts

API

Place a labelled input[role=combobox] and an identified [role=listbox] in a .thin-combobox host with data-enhance=combobox. Options may provide data-value. Replace server results in the document to refresh the observed host.

Behavior tier: dependency-free

Structured host, property, and example tables are not authored for this item yet. Use the summary above and the primary example.

Fallback

Without JavaScript, the labelled named text input submits any typed value and server-rendered suggestions remain readable; provide an ordinary submit button and durable server results page.

Assets and dependencies

  • /components.css
  • /behaviors.js

Dependencies: None

Source: packages/ui/src/items/combobox/style.ts

Composition

Derived from the examples and style specs, not authored.

Composes