Skip to content
Forms

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.

React

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.

Node.js
Bun
+2

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.

PropTypeDefaultDescription
options{ value: string; label: string }[][]The list of selectable options.
valuestring | string[]The controlled selection — an array in multiple mode.
onValueChange(value: string | string[]) => voidFired when the selection changes.
multiplebooleanfalseSelect more than one option, rendered as removable chips.
loadingbooleanfalseShow a loading row in place of results — for options fetched on demand.
onInputChange(query: string) => voidFired as the search query changes. Pair with manualFilter to search server-side.
manualFilterbooleanfalseSkip the built-in filtering and render options exactly as given.
freeSolobooleanfalseAccept values that are not in options by offering to add what was typed.
groupBy(option) => stringGroup options under headings; returns the heading for an option.
limitTagsnumberCollapse chips past this many into a single count badge. Multi-select only.
clearablebooleanfalseShow a button that clears the selection.
disabledbooleanfalseDisable the control.
labelsComboboxLabelsText overrides: placeholder, searchPlaceholder, noResults, loading, clear, create, more, remove.