import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const countries = [
"Australia",
"Brazil",
"Canada",
"Denmark",
"France",
"Germany",
"India",
"Ireland",
"Japan",
"Mexico",
"Netherlands",
"New Zealand",
"Norway",
"Portugal",
"Singapore",
"South Korea",
"Spain",
"Sweden",
"United Kingdom",
"United States",
];
export default function ComboboxBasic() {
return (
<Combobox items={countries}>
<ComboboxInput
placeholder="Select a country"
aria-label="Country"
showClear
className="w-full max-w-xs"
/>
<ComboboxContent>
<ComboboxEmpty>No countries found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}- Add the registryOnce per project
pnpm dlx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json - Add combobox
pnpm dlx shadcn@latest add @jarvis/combobox
Usage
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = ["Astro", "Next.js", "Remix", "SvelteKit", "TanStack Start"];
export function FrameworkCombobox() {
return (
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" aria-label="Framework" />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}Pass the options as items and render each one inside ComboboxList. ComboboxEmpty shows when
nothing matches. Label the input with aria-label or a FieldLabel.
For a short list that doesn't need filtering, use a Select. When people may type a value that isn't an option, use an Autocomplete.
Composition
Examples
Groups
Pass groups as items, each with its own items, and render them with ComboboxGroup and
ComboboxCollection.
import {
Combobox,
ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxLabel,
ComboboxList,
ComboboxSeparator,
} from "@/components/ui/combobox";
const offices = [
{ value: "Americas", items: ["Brazil", "Canada", "Mexico", "United States"] },
{ value: "Europe", items: ["France", "Germany", "Ireland", "Spain", "Sweden"] },
{ value: "Asia Pacific", items: ["Australia", "India", "Japan", "Singapore"] },
];
export default function ComboboxGroups() {
return (
<Combobox items={offices}>
<ComboboxInput
placeholder="Select an office"
aria-label="Office"
className="w-full max-w-xs"
/>
<ComboboxContent>
<ComboboxEmpty>No offices found.</ComboboxEmpty>
<ComboboxList>
{(group: (typeof offices)[number], index: number) => (
<ComboboxGroup key={group.value} items={group.items}>
<ComboboxLabel>{group.value}</ComboboxLabel>
<ComboboxCollection>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxCollection>
{index < offices.length - 1 && <ComboboxSeparator />}
</ComboboxGroup>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}Search in the popup
Use a ComboboxTrigger and put the ComboboxInput inside the popup. For object items,
itemToStringLabel returns the text to search.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from "@/components/ui/combobox";
import { people, type Person } from "@/examples/data";
export default function ComboboxSearchInPopup() {
return (
<Combobox
items={people}
defaultValue={people[0]}
itemToStringLabel={(person: Person) => person.name}
>
<ComboboxTrigger
render={
<Button variant="secondary" className="w-full max-w-xs justify-between font-normal" />
}
>
<ComboboxValue>{(person: Person | null) => person?.name ?? "Assign to…"}</ComboboxValue>
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput showTrigger={false} placeholder="Search people" aria-label="Search people" />
<ComboboxEmpty>No people found.</ComboboxEmpty>
<ComboboxList>
{(person: Person) => (
<ComboboxItem key={person.value} value={person}>
<Avatar size="sm">
<AvatarImage src={person.image} alt="" />
<AvatarFallback>{person.initials}</AvatarFallback>
</Avatar>
{person.name}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}Multiple
Set multiple to show the values as chips in ComboboxChips. Pass the ref from
useComboboxAnchor to ComboboxContent as anchor so the popup lines up with the chips.
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxValue,
useComboboxAnchor,
} from "@/components/ui/combobox";
const labels = [
"Bug",
"Design",
"Documentation",
"Frontend",
"Backend",
"Performance",
"Accessibility",
];
export default function ComboboxMultiple() {
const anchor = useComboboxAnchor();
return (
<Combobox items={labels} multiple autoHighlight defaultValue={["Design", "Frontend"]}>
<ComboboxChips ref={anchor} className="w-full max-w-sm">
<ComboboxValue>
{(values: string[]) => (
<>
{values.map((value) => (
<ComboboxChip key={value}>{value}</ComboboxChip>
))}
<ComboboxChipsInput
aria-label="Labels"
placeholder={values.length > 0 ? "" : "Add labels"}
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxContent anchor={anchor}>
<ComboboxEmpty>No labels found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}Props
ComboboxInput is an Input Group with open and clear buttons.
ComboboxContent takes side, sideOffset, align, alignOffset and anchor.
The tables leave out className, style and render. Parts built on Base UI take them as its styling and composition guides describe.
Combobox
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — |
nameIdentifies the field when a form is submitted. | string | — |
formIdentifies the form that owns the internal input. Useful when the combobox is rendered outside the form. | string | — |
idThe id of the component. | string | — |
requiredWhether the user must choose a value before submitting a form. | boolean | false |
readOnlyWhether the user should be unable to choose a different option from the popup. | boolean | false |
disabledWhether the component should ignore user interaction. | boolean | false |
defaultOpenWhether the popup is initially open. To render a controlled popup, use the | boolean | false |
openWhether the popup is currently open. Use when controlled. | boolean | — |
onOpenChangeCompleteEvent handler called after any animations complete when the popup is opened or closed. | ((open: boolean) => void) | — |
openOnInputClickWhether the popup opens when clicking the input. | boolean | true |
loopFocusWhether to loop keyboard focus back to the input when the end of the list is reached while using the arrow keys. The first item can then be reached by pressing ArrowDown again from the input, or the last item can be reached by pressing ArrowUp from the input. The input is always included in the focus loop per ARIA Authoring Practices. When disabled, focus does not move when on the last element and the user presses ArrowDown, or when on the first element and the user presses ArrowUp. | boolean | true |
inputValueThe input value of the combobox. Use when controlled. | string | number | readonly string[] | — |
defaultInputValueThe uncontrolled input value when initially rendered. To render a controlled input, use the | string | number | readonly string[] | — |
inputRefA ref to the hidden input element. | React.Ref<HTMLInputElement> | — |
gridWhether list items are presented in a grid layout. When enabled, arrow keys navigate across rows and columns inferred from DOM rows. | boolean | false |
itemsThe items to be displayed in the list.
Can be a flat array of items, an array of groups with items, or a collection created by
the | ComboboxItemCollection<unknown, unknown> | readonly any[] | readonly Group<any>[] | — |
filteredItemsFiltered items to display in the list.
When provided, the list uses these items instead of filtering the | readonly unknown[] | readonly Group<unknown>[] | — |
filterFilter function used to match items vs input query.
Receives the source item, which is the derived value's item when | ((item: unknown, query: string, itemToString?: ((item: unknown) => string) | undefined) => boolean) | null | — |
virtualizedWhether the items are being externally virtualized. | boolean | false |
inlineWhether the list is rendered inline without using the component's own popup. Specify In a | boolean | false |
modalDetermines if the popup enters a modal state when open.
On touch devices, a | boolean | false |
limitThe maximum number of items to display in the list. | number | -1 |
localeThe locale to use for string comparison. Defaults to the user's runtime locale. | Intl.LocalesArgument | — |
multipleWhether multiple items can be selected. | boolean | false |
autoCompleteProvides a hint to the browser for autofill. | string | — |
autoHighlightWhether the first matching item is highlighted automatically while filtering. | boolean | false |
highlightItemOnHoverWhether moving the pointer over items should highlight them.
Disabling this prop allows CSS | boolean | true |
itemToStringLabelWhen the item values are objects ( | ((itemValue: unknown) => string) | — |
itemToStringValueWhen the item values are objects ( | ((itemValue: unknown) => string) | — |
isItemEqualToValueCustom comparison logic used to determine if a combobox item value matches the current selected value. Useful when item values are objects without matching referentially.
With a | ((itemValue: unknown, value: unknown) => boolean) | — |
defaultValueThe uncontrolled selected value of the combobox when it's initially rendered. To render a controlled combobox, use the | unknown | — |
actionsRefA ref to imperative actions.
| React.RefObject<AriaCombobox.Actions | null> | — |
onOpenChangeEvent handler called when the popup is opened or closed. | ((open: boolean, eventDetails: Combobox.Root.OpenChangeEventDetails) => void) | — |
onInputValueChangeEvent handler called when the input value changes. | ((inputValue: string, eventDetails: Combobox.Root.ChangeEventDetails) => void) | — |
onItemHighlightedCallback fired when an item is highlighted or unhighlighted.
Receives the highlighted item value (or
| ((highlightedValue: unknown, eventDetails: Combobox.Root.HighlightEventDetails) => void) | — |
valueThe selected value of the combobox. Use when controlled. | unknown | — |
onValueChangeEvent handler called when the selected value of the combobox changes. | ((value: unknown, eventDetails: Combobox.Root.ChangeEventDetails) => void) | — |
ComboboxValue
| Prop | Type | Default |
|---|---|---|
childrenAccepts a function that returns a | ((selectedValue: any) => React.ReactNode) | React.ReactNode | — |
placeholderThe placeholder value to display when no value is selected.
This is overridden by | React.ReactNode | — |
ComboboxTrigger
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native | boolean | true |
ComboboxInput
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |
showTrigger | boolean | true |
showClear | boolean | false |
size | "default" | "lg" | "default" |
ComboboxContent
| Prop | Type | Default |
|---|---|---|
initialFocusDetermines the element to focus when the popup is opened.
| boolean | React.RefObject<HTMLElement | null> | ((openType: InteractionType) => void | boolean | HTMLElement | null) | — |
finalFocusDetermines the element to focus when the popup is closed.
| boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => void | boolean | HTMLElement | null) | — |
anchorAn element to position the popup against. By default, the popup will be positioned against the trigger. | Element | React.RefObject<Element | null> | VirtualElement | (() => Element | VirtualElement | null) | null | — |
sideWhich side of the anchor element to align the popup against. May automatically change to avoid collisions. | "bottom" | "inline-end" | "inline-start" | "left" | "right" | "top" | "bottom" |
sideOffsetDistance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a
| number | OffsetFunction | 4 |
alignHow to align the popup relative to the specified side. | "center" | "end" | "start" | "start" |
alignOffsetAdditional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a
| number | OffsetFunction | 0 |
ComboboxList
| Prop | Type | Default |
|---|---|---|
children | ((item: any, index: number) => React.ReactNode) | React.ReactNode | — |
ComboboxItem
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — |
onClickAn optional click handler for the item when selected.
It fires when clicking the item with the pointer, as well as when pressing | ((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void) | — |
indexThe index of the item in the list. Improves performance when specified by avoiding the need to calculate the index automatically from the DOM. | number | — |
valueA unique value that identifies this item. | any | null |
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native | boolean | false |
ComboboxGroup
| Prop | Type | Default |
|---|---|---|
itemsItems to be rendered within this group.
When provided, child | readonly any[] | — |
ComboboxCollection
| Prop | Type | Default |
|---|---|---|
children | (item: any, index: number) => React.ReactNode | — |
ComboboxSeparator
| Prop | Type | Default |
|---|---|---|
orientationThe orientation of the separator. | "horizontal" | "vertical" | 'horizontal' |
ComboboxChip
| Prop | Type | Default |
|---|---|---|
showRemove | boolean | true |
ComboboxChipsInput
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |