Combobox
A text input bound to a listbox: type to filter, select to commit. Use it when the option list is long enough that a plain select becomes a scroll.
Import
import { Combobox } from "@mikenotthepope/substrateui"Fetching options
onInputChange reports the query so you can fetch for it, and loading shows a spinner while you do. Add manualFilter so the component stops filtering the results you already filtered — without it, a server-side match would be filtered out again on the client.
Accepting new values
freeSolooffers an “Add” row whenever the query matches no existing option, which is what you want for tags and other open-ended fields. The added value is emitted as-is, and it still renders in the trigger even though it is not in options.
Grouping
groupBy returns a heading for each option. Groups appear in first-seen order and filtering applies within them, so an empty group disappears along with its heading.
Chip overflow
Multi-select renders each choice as a removable chip. limitTags keeps a long selection from growing the trigger by collapsing the rest into a count badge, and clearable adds a reset button.
Direction
The chevron indicator and selected-check icon placement flip automatically in RTL — the chevron sits on the start edge (right in RTL) alongside the label. The popover anchors to the trigger and mirrors open-direction, so filtered results still read in the expected order.
Labels
Every string the component renders itself comes from ComboboxLabels, so nothing user-visible is hard-coded English. Override one key or all eight; anything you leave out keeps its default. remove and more take the item label and the overflow count, so they are functions rather than strings.
Set them per instance, or once for the whole app through LabelsProvider.
<Combobox
options={frameworks}
labels={{
placeholder: "Framework auswählen...",
searchPlaceholder: "Suchen...",
noResults: "Kein Framework gefunden.",
loading: "Wird geladen...",
clear: "Auswahl löschen",
create: (query) => `"${query}" hinzufügen`,
more: (count) => `+${count} weitere`,
remove: (label) => `${label} entfernen`,
}}
/>Accessibility
Combobox follows the ARIA combobox pattern via Base UI's Combobox. It supports full keyboard navigation: arrow keys to move through options, Enter to select, Escape to close the listbox.
Always provide a label via Field + FieldLabel or an explicit aria-label. Without one, screen readers will announce the combobox without context.
For multi-select, selected items are rendered as removable Badges. Each remove button is named after the item it removes (“Remove React”), and the clear button carries its own label — override both through labels.remove and labels.clear.
API Reference
The props below are ours. Combobox wraps Base UI's Combobox, so anything not listed here — the open-state props, positioning, and the rest of the primitive's surface — is documented in the Base UI Combobox reference.
| Prop | Type | Default | Description |
|---|---|---|---|
options | { value: string; label: string }[] | [] | The list of selectable options. |
value | string | string[] | — | The controlled selection — an array in multiple mode. |
onValueChange | (value: string | string[]) => void | — | Fired when the selection changes. |
multiple | boolean | false | Select more than one option, rendered as removable chips. |
loading | boolean | false | Show a loading row in place of results — for options fetched on demand. |
onInputChange | (query: string) => void | — | Fired as the search query changes. Pair with manualFilter to search server-side. |
manualFilter | boolean | false | Skip the built-in filtering and render options exactly as given. |
freeSolo | boolean | false | Accept values that are not in options by offering to add what was typed. |
groupBy | (option) => string | — | Group options under headings; returns the heading for an option. |
limitTags | number | — | Collapse chips past this many into a single count badge. Multi-select only. |
clearable | boolean | false | Show a button that clears the selection. |
disabled | boolean | false | Disable the control. |
labels | ComboboxLabels | — | Text overrides: placeholder, searchPlaceholder, noResults, loading, clear, create, more, remove. |