Combobox
An input that filters a list of options as you type.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation, and paste states.ts and state-styles.ts
from the same page. states.ts holds the popup's surface, the items' nested
corner, the chips frame's field surface and focus ring, and the dimmed item. The
list, the items and the chips read their Base UI state through
state-styles.ts. Include interop.css for icon sizing,
button trigger backgrounds and hiding the chevron beside the clear button.
Paste field-state.ts from the same installation page.
Add Input, Input Group
and Button. The input renders inside an
InputGroup frame, and the trigger, clear and chip-remove controls are
buttons.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
Pass the options through items and render each one from the function child
of ComboboxList. Base UI filters items against what is typed, so a list
written as static children does not filter and ComboboxEmpty never shows.
Give the input an aria-label or a Label. There is no Field to name it.
Composition
Simple
With chips
With groups
Custom items
Pass itemToStringLabel when the items are objects. The filter matches against
its result, and the input shows it once an item is picked. Items shaped
{ value, label } need neither.
Basic
A single input over a flat list.
Multiple
Set multiple and swap the input for ComboboxChips. The chosen values render
as ComboboxChips from the function child of ComboboxValue, and
ComboboxChipsInput filters what is left.
Give ComboboxChips the ref from useComboboxAnchor and pass the same ref to
ComboboxContent as anchor. Base UI otherwise positions against the input,
which is only part of the frame.
Clear button
Set showClear on the input. The X is mounted only while there is a value,
and it replaces the chevron while it is shown.
Groups
Pass groups shaped { value, items } to items. Render each one as a
ComboboxGroup with the group's items, a ComboboxLabel and a
ComboboxCollection that renders the items.
Filtering drops a group that has no match left, so a ComboboxSeparator goes
inside the group rather than between groups. Render it before every group but
the first.
Custom items
Render anything inside ComboboxItem. The tick stays at the trailing edge.
Invalid
Set invalid on Field to style its control, or aria-invalid on a bare control. The examples show both.
Disabled
Set disabled on Field to disable its control and dim its label, or on a bare control directly.
Auto highlight
Set autoHighlight on Combobox to highlight the first match as you type, so
Enter picks it.
Popup
Render a ComboboxTrigger as a Button and move ComboboxInput inside
ComboboxContent, with showTrigger={false}. ComboboxValue shows the
current value in the button.
Input group
ComboboxInput is an InputGroup, so an InputGroupAddon passed as its child
renders inside the frame.
API reference
Pass render to replace a part's element or compose it with another component.
Every part wraps the Base UI Combobox part of the same name and accepts its
props. See the Base UI reference
for the full list. Each styled part also takes xstyle and className.
ComboboxList, ComboboxItem and ComboboxChip take style too. It is real
inline CSS, merged over whatever their Base UI state resolves to.
Combobox
| Prop | Type | Default |
|---|---|---|
items | readonly Item[] | readonly Group[] | — |
multiple | boolean | false |
value | Item | Item[] | null | — |
defaultValue | Item | Item[] | null | — |
onValueChange | (value, details) => void | — |
autoHighlight | boolean | false |
itemToStringLabel | (item: Item) => string | — |
filter | (item, query, toString) => boolean | — |
disabled | boolean | false |
name | string | — |
ComboboxInput
| Prop | Type | Default |
|---|---|---|
showTrigger | boolean | true |
showClear | boolean | false |
disabled | boolean | false |
aria-invalid | boolean | — |
xstyle and className apply to the InputGroup frame, not the <input>.
The popup anchors to the frame, so the popup is the frame's width, addons
included.
ComboboxContent
| Prop | Type | Default |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
sideOffset | number | 6 |
align | "start" | "center" | "end" | "start" |
alignOffset | number | 0 |
anchor | Element | RefObject<Element> | — |
The popup is never narrower than 9rem and never taller than 18rem. The
list inside scrolls.
ComboboxItem
| Prop | Type | Default |
|---|---|---|
value | Item | — |
disabled | boolean | false |
ComboboxGroup
| Prop | Type | Default |
|---|---|---|
items | readonly Item[] | — |
ComboboxChip
| Prop | Type | Default |
|---|---|---|
showRemove | boolean | true |
comboboxStyles
The style maps behind the component. Spread them onto any element.
| Key | What it is |
|---|---|
content | The popup box: width, radius, transition |
list | The scrolling list and its padding |
item | An item's row, type and nested corner |
itemHighlighted | The highlight fill and inset ring |
itemDisabled | The dimmed, inert item |
label | A group label |
empty | The empty message |
separator | The hairline between groups |
chips | The multi-select frame, ring and surface |
chip | One chip |
chipsInput | The bare input inside the chips frame |
content carries no surface. The fill and its hairline ring come from
popupSurface. It sets --carbon-popup-radius, and item merges
popupItem, so a row's corner is that radius less the list's inset. A
highlighted item is itemHighlight and itemDisabled is disabled. chips is
the frame's box, focusWithinRing, fieldSurface and the drop with the halo
beside it on :focus-within, all from states in theme/states.ts.
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="combobox-content" | the popup | Popup surface |
data-side, data-align | the popup | Base UI writes them. data-side picks the slide direction |
data-empty | the popup | Base UI writes it when the filter leaves nothing |
data-starting-style, data-ending-style | the popup | Base UI writes them while the popup animates in or out |
data-slot="input-group" | the input frame | The frame ComboboxInput renders |
data-popup-open | the frame, input | Base UI writes it while the popup is open |
data-slot="combobox-trigger" | the chevron | What interop.css hides beside a clear button |
data-slot="combobox-clear" | the clear button | Mounted only while there is a value |
data-slot="combobox-item" | an item | Targets items from a parent |
data-highlighted, data-selected | an item | Base UI writes them |
data-disabled | an item, a chip | Base UI writes it |
data-slot="combobox-chips" | the chips frame | Targets the frame from a parent |
data-slot="combobox-chip" | a chip | Targets a chip from a parent |