"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxDemo() {
return (
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
pnpm dlx shadcn@latest add https://herocn.dev/r/combobox.jsonimport {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox"Pass an items array to Combobox and render items inside ComboboxList using the render prop.
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>Use the following composition to build a Combobox:
Combobox
├── ComboboxInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxItem
└── ComboboxItemMulti-select with multiple, chips, and a chips input.
Combobox
├── ComboboxChips
│ ├── ComboboxValue
│ │ └── ComboboxChip
│ └── ComboboxChipsInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxItem
└── ComboboxItemNested items per group using ComboboxCollection inside each ComboboxGroup, with a separator between groups.
Combobox
├── ComboboxInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxGroup
│ ├── ComboboxLabel
│ └── ComboboxCollection
│ ├── ComboboxItem
│ └── ComboboxItem
├── ComboboxSeparator
└── ComboboxGroup
├── ComboboxLabel
└── ComboboxCollection
├── ComboboxItem
└── ComboboxItemUse multiple, ComboboxChips, ComboboxChip, and ComboboxChipsInput for multi-select.
"use client";
import * as React from "react";
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxValue,
useComboboxAnchor,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxMultiple() {
const anchor = useComboboxAnchor();
return (
<Combobox
multiple
autoHighlight
items={frameworks}
defaultValue={[frameworks[0]]}
>
<ComboboxChips ref={anchor} className="w-full max-w-xs">
<ComboboxValue>
{(values) => (
<React.Fragment>
{values.map((value: string) => (
<ComboboxChip key={value}>{value}</ComboboxChip>
))}
<ComboboxChipsInput />
</React.Fragment>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxContent anchor={anchor}>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Use ComboboxGroup, ComboboxLabel, ComboboxCollection, and ComboboxSeparator to organize items.
"use client";
import {
Combobox,
ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxLabel,
ComboboxList,
ComboboxSeparator,
} from "@/components/ui/combobox";
const timezones = [
{
value: "Americas",
items: [
"(GMT-5) New York",
"(GMT-8) Los Angeles",
"(GMT-6) Chicago",
"(GMT-5) Toronto",
"(GMT-8) Vancouver",
"(GMT-3) São Paulo",
],
},
{
value: "Europe",
items: [
"(GMT+0) London",
"(GMT+1) Paris",
"(GMT+1) Berlin",
"(GMT+1) Rome",
"(GMT+1) Madrid",
"(GMT+1) Amsterdam",
],
},
{
value: "Asia/Pacific",
items: [
"(GMT+9) Tokyo",
"(GMT+8) Shanghai",
"(GMT+8) Singapore",
"(GMT+4) Dubai",
"(GMT+11) Sydney",
"(GMT+9) Seoul",
],
},
] as const;
export function ComboboxGroups() {
return (
<Combobox items={timezones}>
<ComboboxInput placeholder="Select a timezone" />
<ComboboxContent>
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
<ComboboxList>
{(group, index) => (
<ComboboxGroup key={group.value} items={group.items}>
<ComboboxLabel>{group.value}</ComboboxLabel>
<ComboboxCollection>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxCollection>
{index < timezones.length - 1 && <ComboboxSeparator />}
</ComboboxGroup>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Set showClear on ComboboxInput to show a clear button.
"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxClear() {
return (
<Combobox items={frameworks} defaultValue={frameworks[0]}>
<ComboboxInput placeholder="Select a framework" showClear />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Set disabled on ComboboxInput to disable the control.
"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxDisabled() {
return (
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" disabled />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Set aria-invalid="true" on ComboboxInput to show an error state.
"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxInvalid() {
return (
<Field data-invalid className="w-full max-w-48">
<FieldLabel>Framework</FieldLabel>
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" aria-invalid="true" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<FieldError>Please select a framework.</FieldError>
</Field>
);
}
Set autoHighlight on the root Combobox to automatically highlight the first item on filter.
"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxAutoHighlight() {
return (
<Combobox items={frameworks} autoHighlight>
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Use ComboboxTrigger and ComboboxValue to trigger the combobox from a button. Move ComboboxInput inside ComboboxContent.
"use client";
import { Button } from "@/components/ui/button";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from "@/components/ui/combobox";
const countries = [
{ code: "", value: "", continent: "", label: "Select country" },
{
code: "ar",
value: "argentina",
label: "Argentina",
continent: "South America",
},
{ code: "au", value: "australia", label: "Australia", continent: "Oceania" },
{ code: "br", value: "brazil", label: "Brazil", continent: "South America" },
{ code: "ca", value: "canada", label: "Canada", continent: "North America" },
{ code: "cn", value: "china", label: "China", continent: "Asia" },
{
code: "co",
value: "colombia",
label: "Colombia",
continent: "South America",
},
{ code: "eg", value: "egypt", label: "Egypt", continent: "Africa" },
{ code: "fr", value: "france", label: "France", continent: "Europe" },
{ code: "de", value: "germany", label: "Germany", continent: "Europe" },
{ code: "it", value: "italy", label: "Italy", continent: "Europe" },
{ code: "jp", value: "japan", label: "Japan", continent: "Asia" },
{ code: "ke", value: "kenya", label: "Kenya", continent: "Africa" },
{ code: "mx", value: "mexico", label: "Mexico", continent: "North America" },
{
code: "nz",
value: "new-zealand",
label: "New Zealand",
continent: "Oceania",
},
{ code: "ng", value: "nigeria", label: "Nigeria", continent: "Africa" },
{
code: "za",
value: "south-africa",
label: "South Africa",
continent: "Africa",
},
{ code: "kr", value: "south-korea", label: "South Korea", continent: "Asia" },
{
code: "gb",
value: "united-kingdom",
label: "United Kingdom",
continent: "Europe",
},
{
code: "us",
value: "united-states",
label: "United States",
continent: "North America",
},
];
export function ComboboxPopup() {
return (
<Combobox items={countries} defaultValue={countries[0]}>
<ComboboxTrigger
render={
<Button
variant="tertiary"
className="w-64 justify-between font-normal"
>
<ComboboxValue />
</Button>
}
/>
<ComboboxContent className="min-w-(--anchor-width)">
<ComboboxInput
variant="secondary"
showTrigger={false}
placeholder="Search"
/>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.code} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
The Combobox component supports two visual variants:
default (default) — Standard styling, suitable for most use casessecondary — Lower emphasis variant, suitable for use in Surface components"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const;
export function ComboboxVariants() {
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<Combobox items={frameworks}>
<ComboboxInput placeholder="Default" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<Combobox items={frameworks} variant="secondary">
<ComboboxInput placeholder="Secondary" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
</div>
);
}
Place the combobox inside a Surface panel. Use variant="secondary" on Combobox so the input sits cleanly on the surface background.
Select your preferred framework.
"use client";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox";
import { Surface } from "@/components/ui/surface";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export function ComboboxSurface() {
return (
<Surface className="w-full max-w-sm rounded-3xl border p-4">
<h4 className="font-medium text-sm">Framework</h4>
<p className="mt-1 text-muted-foreground text-sm">
Select your preferred framework.
</p>
<div className="mt-4">
<Combobox items={frameworks} variant="secondary">
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
</div>
</Surface>
);
}
To enable RTL support in shadcn/ui, see the RTL configuration guide.
"use client";
import * as React from "react";
import {
type Translations,
useTranslation,
} from "@/components/language-selector";
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxValue,
useComboboxAnchor,
} from "@/components/ui/combobox";
import { Field, FieldLabel } from "@/components/ui/field";
const categories = [
"technology",
"design",
"business",
"marketing",
"education",
"health",
] as const;
const translations: Translations = {
en: {
dir: "ltr",
values: {
label: "Categories",
placeholder: "Add categories",
empty: "No categories found.",
technology: "Technology",
design: "Design",
business: "Business",
marketing: "Marketing",
education: "Education",
health: "Health",
},
},
ar: {
dir: "rtl",
values: {
label: "الفئات",
placeholder: "أضف فئات",
empty: "لم يتم العثور على فئات.",
technology: "التكنولوجيا",
design: "التصميم",
business: "الأعمال",
marketing: "التسويق",
education: "التعليم",
health: "الصحة",
},
},
he: {
dir: "rtl",
values: {
label: "קטגוריות",
placeholder: "הוסף קטגוריות",
empty: "לא נמצאו קטגוריות.",
technology: "טכנולוגיה",
design: "עיצוב",
business: "עסקים",
marketing: "שיווק",
education: "חינוך",
health: "בריאות",
},
},
};
export function ComboboxRtl() {
const { dir, t, language } = useTranslation(translations, "ar");
const anchor = useComboboxAnchor();
const categoryLabels: Record<string, string> = {
technology: t.technology,
design: t.design,
business: t.business,
marketing: t.marketing,
education: t.education,
health: t.health,
};
return (
<Field
dir={dir}
data-lang={dir === "rtl" ? language : undefined}
className="mx-auto w-full max-w-xs"
>
<FieldLabel>{t.label}</FieldLabel>
<Combobox
multiple
autoHighlight
items={categories}
defaultValue={[categories[0]]}
itemToStringValue={(item: (typeof categories)[number]) =>
categoryLabels[item] || item
}
>
<ComboboxChips ref={anchor}>
<ComboboxValue>
{(values) => (
<React.Fragment>
{values.map((value: string) => (
<ComboboxChip key={value}>
{categoryLabels[value] || value}
</ComboboxChip>
))}
<ComboboxChipsInput placeholder={t.placeholder} />
</React.Fragment>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxContent
anchor={anchor}
dir={dir}
data-lang={dir === "rtl" ? language : undefined}
>
<ComboboxEmpty>{t.empty}</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{categoryLabels[item] || item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
</Field>
);
}
The combobox is built on Base UI Combobox. Combobox forwards props to the root; sub-components forward to their corresponding Base UI primitives.
| Prop | Type | Default |
|---|---|---|
| variant | "default" | "secondary" | "default" |
| Prop | Type | Default |
|---|---|---|
| showTrigger | boolean | true |
| showClear | boolean | false |
| variant | "default" | "secondary" | - |
| Prop | Type | Default |
|---|---|---|
| showRemove | boolean | true |
See the Base UI Combobox API reference for all other props (items, value, onValueChange, multiple, autoHighlight, positioning, etc.).