Pick from a list by typing, wrapping the Base UI Combobox. The input filters as you type, the chevron browses the whole list, and the selection is a real value like any form control. For a short fixed list, the Select stays simpler.

Playground

Every control maps to a prop. Try typing a few letters, then clearing; the Code tab always shows the markup for exactly what you've configured.

Variants

Two inputs and a button: bordered is the default, borderless trades the border for a muted fill, and ComboboxTrigger reads like a Select and moves the typing into the popup.

States

Open, highlighted, and selected are live; try the examples. A selection swaps the chevron for a clear button, disabled dims the whole group, invalid turns the border to the danger color, and focus rings the group on every focus, not just keyboard.

Recipes

The parts compose into the usual bigger patterns without extra props; each recipe below is a complete, paste-ready arrangement.

Multiple select. multiple turns the value into an array, and ComboboxChips shows it as removable chips with the input riding inline after them.

Input inside popup. For a select-like control, swap the input for a ComboboxTrigger and put the search field inside the popup with searchInput on the content.

Grouped. Pass groups as the root's items and render each group's own items through ComboboxCollection; filtering reaches into every group.

Creatable. Manage the items yourself and append a create row when the query matches nothing; selecting it adds the value and keeps it chosen.

Async search

Fetch on onInputValueChange, hand the results to items, and keep a status line up while the request runs; with multiple, picked people stay as chips while new searches stream fresh results into the list. Both demos fake the network with a delay.

Styling states

Items carry data-highlighted and data-selected, the chevron carries data-popup-open, and the popup has the usual data-starting-style/data-ending-style transitions:

.ub-combobox-item[data-highlighted] {
  background: var(--ub-accent);
  color: var(--ub-accent-contrast);
}

Props

Everything Base UI's Combobox parts accept passes through (multiple, itemToStringLabel for object items, onInputValueChange, ...). The essentials:

PropTypeDefaultDescription
ComboboxRoot.itemsValue[]The full list; typing filters it and powers the empty state.
ComboboxRoot.valueValue | Value[]Controlled selection (also defaultValue, onValueChange); multiple makes it an array.
ComboboxRoot.size"default" | "compact""default"Sizes the input and the list together: 36px tall with 16px text by default, 28px with 14px text compact.
ComboboxInput.variant"default" | "borderless""default"Bordered, or a muted fill with no border.
ComboboxInput.clearablebooleantrueWhile something is selected, the clear button takes the chevron's place.
ComboboxInput.invalidbooleanfalseDanger border and ring, plus aria-invalid; a surrounding Field sets it automatically. Also on ComboboxTrigger.
ComboboxContent.emptyReactNodeShown while the filter matches nothing.
ComboboxContent.children(item) => ReactNodeCalled with each filtered item; render a ComboboxItem.
ComboboxContent.searchInputboolean | stringPuts the text input inside the popup, for ComboboxTrigger; a string sets its placeholder.
ComboboxContent.statusReactNodeA politely announced status line above the list, for async searches.
ComboboxContent.sideOffsetnumber4Gap between the input and the popup, in pixels. Also side and align.
ComboboxTrigger.placeholderReactNodeShown while nothing is selected; visual only, so name the trigger with aria-label.
ComboboxRoot.itemToStringLabel(item) => stringThe label to show and filter on when items are objects.

Agent instructions

Working with a coding agent? Paste this into its context, or point it at llms.txt for the whole library.

ComboboxRoot, ComboboxInput, ComboboxTrigger, ComboboxContent, ComboboxItem, ComboboxGroup, ComboboxGroupLabel, ComboboxChips, ComboboxChip, ComboboxValue, ComboboxCollection, ComboboxStatus, from @usebones/react.
- Structure: ComboboxRoot (pass items; size "default" | "compact") wraps ComboboxInput (placeholder, variant "default" | "borderless", clearable default true, invalid, disabled; chevron built in, swapped for a clear button while something is selected) + ComboboxContent (empty="..." plus function children rendering a ComboboxItem per filtered item).
- value/defaultValue/onValueChange like every control; multiple turns the value into an array. Object items need itemToStringLabel.
- Multiple with chips: ComboboxChips wrapping ComboboxValue's function children (map values to ComboboxChip; put ComboboxInput clearable={false} after them). Chip remove buttons are automatic.
- Select-like: ComboboxTrigger (placeholder is visual only; name it via aria-label or a Field label) with searchInput="..." on ComboboxContent putting the input inside the popup.
- Grouped: items are groups; function children get each group; ComboboxGroup items={group.items} + ComboboxGroupLabel + ComboboxCollection render the rows.
- Async: fetch in onInputValueChange, pass results as items, status="Searching..." on the content while loading (announced politely), empty={null} while loading.
- Creatable: manage items in state, render static children, and append a ComboboxItem whose value is the query when nothing matches.
- Prefer Select for short fixed lists; the combobox earns its input when the list is long enough to search.
- Inside FieldRoot, drop invalid and use FieldLabel and FieldError instead; the Field wires the name and validation.
- Restyle in CSS via .ub-combobox-input-group ([data-variant], [data-size]), .ub-combobox-input ([data-invalid], [data-disabled]), .ub-combobox-chips, .ub-combobox-chip, .ub-combobox-popup, .ub-combobox-item ([data-highlighted], [data-selected]), [data-popup-open] on the chevron. Tokens only.