Forms
Combobox
A select you can type into.
When to reach for it
Examples
default
Type to filter — “compact” matches two of them.
multiple
The panel stays open while you pick; past two it counts instead of listing.
Notes
A select you can type into, choosing one or several.
The line against Select is length, and it is not a matter of taste: a styled select is better up to roughly a dozen options, because a list nobody can filter is faster to scan than one they have to think about. Past that, this is the right answer.
Filtering, the highlighted row and the arrow keys come from cmdk, which implements the ARIA combobox pattern properly: the highlight moves through aria-activedescendant while focus stays in the input. Hand-rolled comboboxes move focus into the list instead, and the typed text stops being editable.
Controlled or uncontrolled, like every other form control here.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | Names the control. Required — the trigger's text is a value, not a label. | |
| optionsrequired | ComboboxOption[] | — | |
| className | string | — | |
| defaultValue | string | — | |
| disabled | boolean | false | — |
| emptyMessage | string | 'Nothing matches.' | Shown when the filter matches nothing. Say what WOULD match. |
| multiple | false | — | |
| onValueChange | (value: string) => void | — | |
| placeholder | string | 'Select…' | Shown on the trigger when nothing is chosen. |
| searchPlaceholder | string | 'Search…' | Placeholder inside the filter field. |
| value | string | — |
Keyboard
| Key | Does |
|---|---|
| EnterSpace↓ | Opens the list. |
| ↑↓ | Moves the highlight while focus stays in the filter. |
| Enter | Chooses the highlighted option; choosing the current one clears it. |
| Escape | Closes without choosing. |
Accessibility
- The highlight moves through aria-activedescendant while focus stays in the input — the ARIA combobox pattern. Hand-rolled comboboxes move focus into the list, and the typed text stops being editable.
- label is required: the trigger prints a value, and a value is not a name.