Combobox

Filterable single-select with an animated custom listbox, built on the dropdown open/close machine

Category: inputs · WCAG 2.2-AA · select, combobox, dropdown, filter, search

Sizes

States

Props

PropTypeDefaultDescription
idstringBase id for the input and its listbox/aria wiring; auto-generated when omitted.
optionsComboboxOption[]The selectable options.
valuestringThe controlled value.
defaultValuestringThe initial value when uncontrolled.
onValueChange(value: string | undefined) => voidCalled with the selected option value (or undefined when cleared).
clearablebooleanfalseWhen true, shows a control to clear the selected value.
searchablebooleantrueWhen true the field is a text input that filters the list as the user types (the APG editable combobox). When false it is a button that opens the list, and type-to-select jumps to a matching option (the APG select-only combobox).
loadingbooleanfalseWhen true, the list reports itself as busy and shows a loading row instead of the empty message.
onSearchChange(query: string) => voidCalled with the search text on every keystroke. Pair it with filter={() => true} for a server-driven list.
filter(option: ComboboxOption, query: string) => booleanReplaces the built-in diacritic-insensitive matcher.
creatablebooleanfalseWhen true, offers the current search text as a new option.
onCreate(label: string) => voidCalled with the typed label when the user picks the "create" row.
namestringSubmitted with a surrounding form — a hidden input carrying the selected value.
requiredbooleanMarks the control as required for assistive technology.
openbooleanControlled open state of the listbox.
defaultOpenbooleanfalseThe initial open state when uncontrolled.
onOpenChange(open: boolean) => voidCalled when the listbox opens or closes.
labelstringText label for the control.
hintstringSupplementary hint text shown with the control.
errorstringError message shown when the value is invalid.
size'sm' | 'md' | 'lg''md'Visual size of the component (e.g. 'sm', 'md', 'lg').
disabledbooleanfalseWhen true, disables the control and removes it from the tab order.
labelsComboboxLabelsOverrides for the component’s user-visible strings (i18n).
classNamestringAdditional CSS class names merged onto the root element.
aria-labelledbystringWired automatically by a wrapping `Field` — its label id, forwarded to the focusable control so the Field's label names it.
aria-describedbystringWired automatically by a wrapping `Field` — the ids of its hint/error text, forwarded to the focusable control so the supporting text is announced.
aria-invalidbooleanWired automatically by a wrapping `Field` when it is in an error state.
ariaLabelstringInvisible accessible name, for when a visible element outside this component already labels it and `label` would render that text a second time. ⚠ `label` on this component is **visible**; `IconButton.label`/`Sparkline.label` are invisible names, which is the prior that costs adopters a duplicated label. The raw DOM `aria-label` still wins over this.

Design tokens

When to use

When not to use

How to build an accessible Combobox in React →

Examples

Grouped options

Options carrying a group render under a labelled role="group" heading.

<Combobox options={[{value:'de',label:'Germany',group:'Europe'},{value:'jp',label:'Japan',group:'Asia'}]} />

Remote search

filter={() => true} hands filtering to the server; loading marks the list busy between keystroke and response.

<Combobox options={results} loading={pending} onSearchChange={search} filter={() => true} />

Select-only

A button rather than a text field; printable characters type-to-select, and Home/End jump the list.

<Combobox options={options} searchable={false} />

Basic combobox

<Combobox
  label="Country"
  options={[
    { value: 'us', label: 'United States' },
    { value: 'de', label: 'Germany' },
    { value: 'fr', label: 'France' },
  ]}
  onValueChange={(value) => console.log(value)}
/>

Related components

← Back to docs