Combobox
An autocomplete input that filters a popup list as you type, built on Base UI. Single or multiple selection, with a chips layout for multi-select.
Playground
<Combobox items={fruits}>
<ComboboxInput placeholder="Pick a fruit..." />
<ComboboxContent>
<ComboboxList>
<ComboboxCollection>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxCollection>
</ComboboxList>
<ComboboxEmpty>No fruits found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>Preview
Pass items to the root, an ComboboxInput to type into, and a ComboboxContent popup with a ComboboxCollection render function for the filtered items.
const fruits = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
]
// Passing the whole { value, label } object as the item value makes the
// input display the label and forms submit the value – automatically.
<Combobox items={fruits}>
<ComboboxInput placeholder="Pick a fruit..." />
<ComboboxContent>
<ComboboxList>
<ComboboxCollection>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxCollection>
</ComboboxList>
<ComboboxEmpty>No results found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/combobox.jsonUsage
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxLabel,
ComboboxList,
ComboboxSeparator,
ComboboxTrigger,
ComboboxValue,
useComboboxAnchor,
} from "@/components/ui/combobox"<Combobox items={items}>
<ComboboxInput placeholder="Search..." />
<ComboboxContent>
<ComboboxList>
<ComboboxCollection>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxCollection>
</ComboboxList>
<ComboboxEmpty>No results found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>Variants
variant on the root styles the input surface: outline (default, raised background with shadow), subtle (filled secondary surface) and ghost (transparent until focused).
<Combobox variant="outline" items={fruits}>...</Combobox>
<Combobox variant="subtle" items={fruits}>...</Combobox>
<Combobox variant="ghost" items={fruits}>...</Combobox>Sizes
size on the root scales the input, the popup radius and the item density: xs, sm, md (default) and lg.
<Combobox size="xs" items={fruits}>...</Combobox>
<Combobox size="sm" items={fruits}>...</Combobox>
<Combobox size="md" items={fruits}>...</Combobox>
<Combobox size="lg" items={fruits}>...</Combobox>Grouped items
Wrap items in ComboboxGroup with a ComboboxLabel heading, and divide groups with ComboboxSeparator.
<Combobox>
<ComboboxInput placeholder="Search produce..." />
<ComboboxContent>
<ComboboxList>
<ComboboxGroup>
<ComboboxLabel>Fruits</ComboboxLabel>
{fruits.map((item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
))}
</ComboboxGroup>
<ComboboxSeparator />
<ComboboxGroup>
<ComboboxLabel>Vegetables</ComboboxLabel>
{vegetables.map((item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
))}
</ComboboxGroup>
</ComboboxList>
<ComboboxEmpty>No items found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>Multi-select chips
With multiple, render the selection as removable chips: ComboboxChips wraps ComboboxChip entries and a ComboboxChipsInput. Use the exported useComboboxAnchor ref so the popup anchors to the whole chips container instead of the inline input.
const [value, setValue] = React.useState([fruits[0], fruits[2]])
const anchorRef = useComboboxAnchor()
<Combobox multiple items={fruits} value={value} onValueChange={setValue}>
<ComboboxChips ref={anchorRef}>
{value.map((item) => (
<ComboboxChip key={item.value}>
<ComboboxValue>{item.label}</ComboboxValue>
</ComboboxChip>
))}
<ComboboxChipsInput placeholder="Add fruits..." />
</ComboboxChips>
<ComboboxContent anchor={anchorRef}>
<ComboboxList>...</ComboboxList>
<ComboboxEmpty>No fruits found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>API reference
Combobox wraps the Base UI Combobox root and shares its variant and size with every part via context. The root also accepts all Base UI root props – items, value, defaultValue, onValueChange, multiple and disabled. When item values are objects shaped { value, label }, the input displays the label and forms submit the value automatically; other object shapes can map themselves with itemToStringLabel (display) and itemToStringValue (form submission).
Combobox
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "outline" | "subtle" | "ghost" | "outline" | Input surface style, shared with all parts via context. |
| size | "xs" | "sm" | "md" | "lg" | "md" | Scales the input, popup radius, item density and chips. |
| items | TItem[] | – | Options to filter as the user types. Objects with label/value work with the default filtering. |
| multiple | boolean | false | Allow selecting several values; pair with the chips layout. |
| value / onValueChange | TItemValue | TItemValue[] | – | Controlled selection and its change handler. |
ComboboxInput
| Prop | Type | Default | Description |
|---|---|---|---|
| showTrigger | boolean | true | Show the chevron button that opens the popup at the trailing edge. |
| showClear | boolean | false | Show a clear button that resets the selection. When visible it replaces the trigger chevron. |
ComboboxContent
| Prop | Type | Default | Description |
|---|---|---|---|
| side | "top" | "right" | "bottom" | "left" | "bottom" | Which side of the anchor the popup opens on. |
| sideOffset | number | 6 | Gap between the anchor and the popup. |
| align | "start" | "center" | "end" | "start" | Alignment against the anchor. |
| alignOffset | number | 0 | Offset along the alignment axis. |
| anchor | React.RefObject<HTMLElement> | – | Custom anchor element – pass the useComboboxAnchor ref to anchor the popup to a ComboboxChips container. |
ComboboxChip
| Prop | Type | Default | Description |
|---|---|---|---|
| showRemove | boolean | true | Render the small remove (x) button inside the chip. |
| Component | Description |
|---|---|
| ComboboxInput | Single-select text input rendered inside an InputGroup, with a built-in trigger chevron and optional clear button. |
| ComboboxContent | Portalled popup (data-slot="combobox-content") sized to the anchor width, with open/close animations. |
| ComboboxList | Scrollable option list (data-slot="combobox-list") with scroll fade and max height. |
| ComboboxItem | Selectable option (data-slot="combobox-item") with highlight styles and a trailing check indicator when selected. |
| ComboboxCollection | Render-function wrapper (data-slot="combobox-collection") that maps the filtered items to elements. |
| ComboboxGroup / ComboboxLabel | Option group (data-slot="combobox-group") with a small heading (data-slot="combobox-label"). |
| ComboboxSeparator | Thin divider between groups (data-slot="combobox-separator"). |
| ComboboxEmpty | Message shown when no items match the query (data-slot="combobox-empty"). |
| ComboboxChips / ComboboxChip / ComboboxChipsInput | Multi-select layout: chips container (data-slot="combobox-chips"), a removable chip per value (data-slot="combobox-chip", remove button data-slot="combobox-chip-remove") and the inline input (data-slot="combobox-chip-input"). |
| ComboboxTrigger | Standalone popup trigger with a chevron icon (data-slot="combobox-trigger"), used internally by ComboboxInput. |
| ComboboxValue | Renders the selected value label (data-slot="combobox-value"), e.g. inside a chip. |
| useComboboxAnchor | Convenience hook returning a ref to share between ComboboxChips and ComboboxContent anchor. |
Accessibility & styling hooks
Base UI wires up the full combobox ARIA pattern – the input gets role="combobox" with aria-expanded, the popup is a listbox whose options report aria-selected, and arrow keys, Enter and Escape work out of the box. Every part exposes a data-slot attribute (see the parts table above), variant-aware parts also reflect data-variant and data-size, and the popup carries Base UI state attributes like data-open and data-side – target these from CSS for app-level overrides.