- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Calendar
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- OTP Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Segmented ControlNew
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Combobox
An input combined with a list of predefined items to select.
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxInput aria-label="Select a item" placeholder="Select a item…" />
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Installation
pnpm dlx shadcn@latest add @coss/combobox
Usage
Single Selection
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
createComboboxItems,
} from "@/components/ui/combobox"const items = [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "orange", label: "Orange" },
{ value: "grape", label: "Grape" },
]
<Combobox items={items}>
<ComboboxInput placeholder="Select an item..." />
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem key={item.value} value={item}>{item.label}</ComboboxItem>}
</ComboboxList>
</ComboboxPopup>
</Combobox>When your source items are objects but selection should use a stable primitive value, create a typed collection with createComboboxItems:
const users = [
{ id: "ada", name: "Ada Lovelace" },
{ id: "grace", name: "Grace Hopper" },
]
const userItems = createComboboxItems(users, {
getLabel: (user) => user.name,
getValue: (user) => user.id,
})
<Combobox defaultValue="ada" items={userItems}>
<ComboboxInput placeholder="Select a user..." />
<ComboboxPopup>
<ComboboxList>
{(user) => (
<ComboboxItem key={user.id} value={user.id}>
{user.name}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>Multiple Selection
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxValue,
} from "@/components/ui/combobox"const items = [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "orange", label: "Orange" },
{ value: "grape", label: "Grape" },
]
<Combobox items={items} multiple>
<ComboboxChips>
<ComboboxValue>
{(value: { value: string; label: string }[]) => (
<>
{value?.map((item) => (
<ComboboxChip key={item.value} aria-label={item.value}>
{item.label}
</ComboboxChip>
))}
<ComboboxChipsInput
placeholder={value.length > 0 ? undefined : "Select an item..."}
aria-label="Select an item"
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem value={item}>{item.label}</ComboboxItem>}
</ComboboxList>
</ComboboxPopup>
</Combobox>API Reference
Combobox
The root combobox component. Manages the combobox state and provides context to child components.
| Prop | Type | Description |
|---|---|---|
items | readonly unknown[] | The array of items to display in the combobox |
multiple | boolean | Whether to allow multiple selection |
open | boolean | Controls whether the popup is open |
...props | React.ComponentProps<typeof Combobox> | All Base UI Combobox props are supported |
createComboboxItems
Creates a typed item collection that derives primitive selection values and labels from object items. Define static collections outside components and memoize dynamic collections.
ComboboxInput
The input field component for single selection mode with extended features for size variants and addon support.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | The size variant of the input field |
startAddon | React.ReactNode | - | Element to display at the start (left side) of the input, such as an icon |
showTrigger | boolean | true | Whether to display a trigger button (chevron icon) on the right side of the input |
showClear | boolean | false | Whether to display a clear button (X icon) on the right side of the input when there is a value |
triggerProps | Combobox.Trigger.Props | - | Props forwarded to the internal trigger button, useful for overriding aria-label |
clearProps | Combobox.Clear.Props | - | Props forwarded to the internal clear button, useful for overriding aria-label |
className | string | - | Additional CSS classes to apply to the component |
...props | Base UI Combobox Input props | - | All standard combobox input attributes are supported |
ComboboxPopup
The popup container that displays the combobox options.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes to apply to the component |
portalProps | Combobox.Portal.Props | Props forwarded to the internal portal (keepMounted, container, etc.); see Base UI Combobox portal API |
...props | Base UI Combobox Popup props | All standard combobox popup attributes are supported |
ComboboxList
A scrollable container for combobox items.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox List props | All standard combobox list attributes are supported |
ComboboxItem
An individual selectable combobox item.
| Prop | Type | Description |
|---|---|---|
value | unknown | The value of the item |
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox Item props | All standard combobox item attributes are supported |
ComboboxEmpty
Displays a message when no results are found.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox Empty props | All standard combobox empty attributes are supported |
ComboboxGroup
Groups related combobox items together.
| Prop | Type | Description |
|---|---|---|
items | readonly unknown[] | The array of items in this group |
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox Group props | All standard combobox group attributes are supported |
ComboboxGroupLabel
Displays a label for a combobox group.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox Group Label props | All standard combobox group label attributes are supported |
ComboboxCollection
Used to wrap items within a group for rendering.
| Prop | Type | Description |
|---|---|---|
...props | Base UI Combobox Collection props | All standard combobox collection attributes are supported |
ComboboxChips
Container for displaying selected chips in multiple selection mode.
| Prop | Type | Description |
|---|---|---|
startAddon | React.ReactNode | Element to display at the start (left side) of the chips area |
className | string | Additional CSS classes to apply to the component |
...props | React.ComponentProps<'div'> | All standard div attributes are supported |
ComboboxChipsInput
The input field component for use inside ComboboxChips in multiple selection mode. This is a minimal input without the wrapper, trigger, or clear button.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | The size variant of the input field |
className | string | - | Additional CSS classes to apply to the component |
...props | Base UI Combobox Input props | - | All standard combobox input attributes are supported |
ComboboxChip
An individual chip representing a selected item in multiple selection mode.
| Prop | Type | Description |
|---|---|---|
removeProps | Combobox.ChipRemove.Props | Props forwarded to the internal remove button, useful for overriding aria-label |
className | string | Additional CSS classes to apply to the component |
...props | Base UI Combobox Chip props | All standard combobox chip attributes are supported |
ComboboxValue
Provides access to the current value for custom rendering.
| Prop | Type | Description |
|---|---|---|
...props | Base UI Combobox Value props | All standard combobox value attributes are supported |
Examples
Disabled
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox defaultValue={items[2]} disabled items={items}>
<ComboboxInput
aria-label="Select an item"
placeholder="Select an item…"
/>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Small Size
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxInput
aria-label="Select an item"
placeholder="Select an item..."
size="sm"
/>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Large Size
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxInput
aria-label="Select an item"
placeholder="Select an item..."
size="lg"
/>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Label
"use client";
import { useId } from "react";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
import { Label } from "@/components/ui/label";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
const id = useId();
return (
<Combobox items={items}>
<div className="flex flex-col items-start gap-2">
<Label htmlFor={id}>Fruits</Label>
<ComboboxInput
aria-label="Select an item"
id={id}
placeholder="Select an item..."
/>
</div>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Auto Highlight
Automatically highlight the first matching option.
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox autoHighlight items={items}>
<ComboboxInput
aria-label="Select an item"
placeholder="Select an item..."
/>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Clear Button
"use client";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxInput
aria-label="Select a item"
placeholder="Select a item…"
showClear
/>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Groups
"use client";
import { Fragment } from "react";
import {
Combobox,
ComboboxCollection,
ComboboxEmpty,
ComboboxGroup,
ComboboxGroupLabel,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxSeparator,
} from "@/components/ui/combobox";
// Grouped items demo
type Tag = { id: string; label: string; group: "Status" | "Priority" | "Team" };
type TagGroup = { value: string; items: Tag[] };
const tagsData: Tag[] = [
// Status
{ group: "Status", id: "s-open", label: "Open" },
{ group: "Status", id: "s-in-progress", label: "In progress" },
{ group: "Status", id: "s-blocked", label: "Blocked" },
{ group: "Status", id: "s-resolved", label: "Resolved" },
{ group: "Status", id: "s-closed", label: "Closed" },
// Priority
{ group: "Priority", id: "p-low", label: "Low" },
{ group: "Priority", id: "p-medium", label: "Medium" },
{ group: "Priority", id: "p-high", label: "High" },
{ group: "Priority", id: "p-urgent", label: "Urgent" },
// Team
{ group: "Team", id: "t-design", label: "Design" },
{ group: "Team", id: "t-frontend", label: "Frontend" },
{ group: "Team", id: "t-backend", label: "Backend" },
{ group: "Team", id: "t-devops", label: "DevOps" },
{ group: "Team", id: "t-qa", label: "QA" },
{ group: "Team", id: "t-mobile", label: "Mobile" },
{ group: "Team", id: "t-data", label: "Data" },
{ group: "Team", id: "t-security", label: "Security" },
{ group: "Team", id: "t-platform", label: "Platform" },
{ group: "Team", id: "t-infra", label: "Infrastructure" },
{ group: "Team", id: "t-product", label: "Product" },
{ group: "Team", id: "t-marketing", label: "Marketing" },
{ group: "Team", id: "t-sales", label: "Sales" },
{ group: "Team", id: "t-support", label: "Support" },
{ group: "Team", id: "t-research", label: "Research" },
{ group: "Team", id: "t-content", label: "Content" },
{ group: "Team", id: "t-analytics", label: "Analytics" },
{ group: "Team", id: "t-operations", label: "Operations" },
{ group: "Team", id: "t-finance", label: "Finance" },
{ group: "Team", id: "t-hr", label: "HR" },
{ group: "Team", id: "t-legal", label: "Legal" },
{ group: "Team", id: "t-growth", label: "Growth" },
{ group: "Team", id: "t-partner", label: "Partner" },
{ group: "Team", id: "t-community", label: "Community" },
{ group: "Team", id: "t-docs", label: "Docs" },
{ group: "Team", id: "t-l10n", label: "Localization" },
{ group: "Team", id: "t-a11y", label: "Accessibility" },
{ group: "Team", id: "t-sre", label: "SRE" },
{ group: "Team", id: "t-release", label: "Release" },
{ group: "Team", id: "t-architecture", label: "Architecture" },
{ group: "Team", id: "t-ux", label: "UX" },
{ group: "Team", id: "t-ui", label: "UI" },
{ group: "Team", id: "t-management", label: "Management" },
];
function groupTags(tags: Tag[]): TagGroup[] {
const groups: Record<string, Tag[]> = {};
for (const tag of tags) {
if (!groups[tag.group]) {
groups[tag.group] = [];
}
groups[tag.group]?.push(tag);
}
const order: Array<TagGroup["value"]> = ["Status", "Priority", "Team"];
return order.map((value) => ({ items: groups[value] ?? [], value }));
}
const groupedTags: TagGroup[] = groupTags(tagsData);
export default function Particle() {
return (
<Combobox items={groupedTags}>
<div className="flex flex-col items-start gap-2">
<ComboboxInput aria-label="Search tags" placeholder="e.g. feature" />
</div>
<ComboboxPopup>
<ComboboxEmpty>No tags found.</ComboboxEmpty>
<ComboboxList>
{(group: TagGroup) => (
<Fragment key={group.value}>
<ComboboxGroup items={group.items}>
<ComboboxGroupLabel>{group.value}</ComboboxGroupLabel>
<ComboboxCollection>
{(tag: Tag) => (
<ComboboxItem key={tag.id} value={tag}>
{tag.label}
</ComboboxItem>
)}
</ComboboxCollection>
</ComboboxGroup>
{group.value !== "Team" && <ComboboxSeparator />}
</Fragment>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Multiple Selection
"use client";
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxValue,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox defaultValue={[items[0], items[4]]} items={items} multiple>
<ComboboxChips>
<ComboboxValue>
{(value: { value: string; label: string }[]) => (
<>
{value?.map((item) => (
<ComboboxChip aria-label={item.label} key={item.value}>
{item.label}
</ComboboxChip>
))}
<ComboboxChipsInput
aria-label="Select a item"
placeholder={value.length > 0 ? undefined : "Select a item..."}
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Start Addon
Display an icon or other element at the start of the input using the startAddon prop.
"use client";
import { SearchIcon } from "lucide-react";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxInput
aria-label="Search items"
placeholder="Search items…"
startAddon={<SearchIcon />}
/>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Start Addon - Multiple
Use the startAddon prop on ComboboxChips to display an icon at the start when using multiple selection.
"use client";
import { SearchIcon } from "lucide-react";
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxValue,
} from "@/components/ui/combobox";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox defaultValue={[items[0], items[3]]} items={items} multiple>
<ComboboxChips startAddon={<SearchIcon />}>
<ComboboxValue>
{(value: { value: string; label: string }[]) => (
<>
{value?.map((item) => (
<ComboboxChip aria-label={item.label} key={item.value}>
{item.label}
</ComboboxChip>
))}
<ComboboxChipsInput
aria-label="Select a item"
placeholder={value.length > 0 ? undefined : "Select a item..."}
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Input Inside Popup
"use client";
import { ChevronsUpDownIcon, SearchIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxTrigger,
ComboboxValue,
} from "@/components/ui/combobox";
interface Country {
code: string;
value: string | null;
continent: string;
label: string;
}
const countries: Country[] = [
{ code: "", continent: "", label: "Select country", value: null },
{ code: "af", continent: "Asia", label: "Afghanistan", value: "afghanistan" },
{ code: "al", continent: "Europe", label: "Albania", value: "albania" },
{ code: "dz", continent: "Africa", label: "Algeria", value: "algeria" },
{ code: "ad", continent: "Europe", label: "Andorra", value: "andorra" },
{ code: "ao", continent: "Africa", label: "Angola", value: "angola" },
{
code: "ar",
continent: "South America",
label: "Argentina",
value: "argentina",
},
{ code: "am", continent: "Asia", label: "Armenia", value: "armenia" },
{ code: "au", continent: "Oceania", label: "Australia", value: "australia" },
{ code: "at", continent: "Europe", label: "Austria", value: "austria" },
{ code: "az", continent: "Asia", label: "Azerbaijan", value: "azerbaijan" },
{
code: "bs",
continent: "North America",
label: "Bahamas",
value: "bahamas",
},
{ code: "bh", continent: "Asia", label: "Bahrain", value: "bahrain" },
{ code: "bd", continent: "Asia", label: "Bangladesh", value: "bangladesh" },
{
code: "bb",
continent: "North America",
label: "Barbados",
value: "barbados",
},
{ code: "by", continent: "Europe", label: "Belarus", value: "belarus" },
{ code: "be", continent: "Europe", label: "Belgium", value: "belgium" },
{ code: "bz", continent: "North America", label: "Belize", value: "belize" },
{ code: "bj", continent: "Africa", label: "Benin", value: "benin" },
{ code: "bt", continent: "Asia", label: "Bhutan", value: "bhutan" },
{
code: "bo",
continent: "South America",
label: "Bolivia",
value: "bolivia",
},
{
code: "ba",
continent: "Europe",
label: "Bosnia and Herzegovina",
value: "bosnia-and-herzegovina",
},
{ code: "bw", continent: "Africa", label: "Botswana", value: "botswana" },
{ code: "br", continent: "South America", label: "Brazil", value: "brazil" },
{ code: "bn", continent: "Asia", label: "Brunei", value: "brunei" },
{ code: "bg", continent: "Europe", label: "Bulgaria", value: "bulgaria" },
{
code: "bf",
continent: "Africa",
label: "Burkina Faso",
value: "burkina-faso",
},
{ code: "bi", continent: "Africa", label: "Burundi", value: "burundi" },
{ code: "kh", continent: "Asia", label: "Cambodia", value: "cambodia" },
{ code: "cm", continent: "Africa", label: "Cameroon", value: "cameroon" },
{ code: "ca", continent: "North America", label: "Canada", value: "canada" },
{ code: "cv", continent: "Africa", label: "Cape Verde", value: "cape-verde" },
{
code: "cf",
continent: "Africa",
label: "Central African Republic",
value: "central-african-republic",
},
{ code: "td", continent: "Africa", label: "Chad", value: "chad" },
{ code: "cl", continent: "South America", label: "Chile", value: "chile" },
{ code: "cn", continent: "Asia", label: "China", value: "china" },
{
code: "co",
continent: "South America",
label: "Colombia",
value: "colombia",
},
{ code: "km", continent: "Africa", label: "Comoros", value: "comoros" },
{ code: "cg", continent: "Africa", label: "Congo", value: "congo" },
{
code: "cr",
continent: "North America",
label: "Costa Rica",
value: "costa-rica",
},
{ code: "hr", continent: "Europe", label: "Croatia", value: "croatia" },
{ code: "cu", continent: "North America", label: "Cuba", value: "cuba" },
{ code: "cy", continent: "Asia", label: "Cyprus", value: "cyprus" },
{
code: "cz",
continent: "Europe",
label: "Czech Republic",
value: "czech-republic",
},
{ code: "dk", continent: "Europe", label: "Denmark", value: "denmark" },
{ code: "dj", continent: "Africa", label: "Djibouti", value: "djibouti" },
{
code: "dm",
continent: "North America",
label: "Dominica",
value: "dominica",
},
{
code: "do",
continent: "North America",
label: "Dominican Republic",
value: "dominican-republic",
},
{
code: "ec",
continent: "South America",
label: "Ecuador",
value: "ecuador",
},
{ code: "eg", continent: "Africa", label: "Egypt", value: "egypt" },
{
code: "sv",
continent: "North America",
label: "El Salvador",
value: "el-salvador",
},
{
code: "gq",
continent: "Africa",
label: "Equatorial Guinea",
value: "equatorial-guinea",
},
{ code: "er", continent: "Africa", label: "Eritrea", value: "eritrea" },
{ code: "ee", continent: "Europe", label: "Estonia", value: "estonia" },
{ code: "et", continent: "Africa", label: "Ethiopia", value: "ethiopia" },
{ code: "fj", continent: "Oceania", label: "Fiji", value: "fiji" },
{ code: "fi", continent: "Europe", label: "Finland", value: "finland" },
{ code: "fr", continent: "Europe", label: "France", value: "france" },
{ code: "ga", continent: "Africa", label: "Gabon", value: "gabon" },
{ code: "gm", continent: "Africa", label: "Gambia", value: "gambia" },
{ code: "ge", continent: "Asia", label: "Georgia", value: "georgia" },
{ code: "de", continent: "Europe", label: "Germany", value: "germany" },
{ code: "gh", continent: "Africa", label: "Ghana", value: "ghana" },
{ code: "gr", continent: "Europe", label: "Greece", value: "greece" },
{
code: "gd",
continent: "North America",
label: "Grenada",
value: "grenada",
},
{
code: "gt",
continent: "North America",
label: "Guatemala",
value: "guatemala",
},
{ code: "gn", continent: "Africa", label: "Guinea", value: "guinea" },
{
code: "gw",
continent: "Africa",
label: "Guinea-Bissau",
value: "guinea-bissau",
},
{ code: "gy", continent: "South America", label: "Guyana", value: "guyana" },
{ code: "ht", continent: "North America", label: "Haiti", value: "haiti" },
{
code: "hn",
continent: "North America",
label: "Honduras",
value: "honduras",
},
{ code: "hu", continent: "Europe", label: "Hungary", value: "hungary" },
{ code: "is", continent: "Europe", label: "Iceland", value: "iceland" },
{ code: "in", continent: "Asia", label: "India", value: "india" },
{ code: "id", continent: "Asia", label: "Indonesia", value: "indonesia" },
{ code: "ir", continent: "Asia", label: "Iran", value: "iran" },
{ code: "iq", continent: "Asia", label: "Iraq", value: "iraq" },
{ code: "ie", continent: "Europe", label: "Ireland", value: "ireland" },
{ code: "il", continent: "Asia", label: "Israel", value: "israel" },
{ code: "it", continent: "Europe", label: "Italy", value: "italy" },
{
code: "jm",
continent: "North America",
label: "Jamaica",
value: "jamaica",
},
{ code: "jp", continent: "Asia", label: "Japan", value: "japan" },
{ code: "jo", continent: "Asia", label: "Jordan", value: "jordan" },
{ code: "kz", continent: "Asia", label: "Kazakhstan", value: "kazakhstan" },
{ code: "ke", continent: "Africa", label: "Kenya", value: "kenya" },
{ code: "kw", continent: "Asia", label: "Kuwait", value: "kuwait" },
{ code: "kg", continent: "Asia", label: "Kyrgyzstan", value: "kyrgyzstan" },
{ code: "la", continent: "Asia", label: "Laos", value: "laos" },
{ code: "lv", continent: "Europe", label: "Latvia", value: "latvia" },
{ code: "lb", continent: "Asia", label: "Lebanon", value: "lebanon" },
{ code: "ls", continent: "Africa", label: "Lesotho", value: "lesotho" },
{ code: "lr", continent: "Africa", label: "Liberia", value: "liberia" },
{ code: "ly", continent: "Africa", label: "Libya", value: "libya" },
{
code: "li",
continent: "Europe",
label: "Liechtenstein",
value: "liechtenstein",
},
{ code: "lt", continent: "Europe", label: "Lithuania", value: "lithuania" },
{ code: "lu", continent: "Europe", label: "Luxembourg", value: "luxembourg" },
{ code: "mg", continent: "Africa", label: "Madagascar", value: "madagascar" },
{ code: "mw", continent: "Africa", label: "Malawi", value: "malawi" },
{ code: "my", continent: "Asia", label: "Malaysia", value: "malaysia" },
{ code: "mv", continent: "Asia", label: "Maldives", value: "maldives" },
{ code: "ml", continent: "Africa", label: "Mali", value: "mali" },
{ code: "mt", continent: "Europe", label: "Malta", value: "malta" },
{
code: "mh",
continent: "Oceania",
label: "Marshall Islands",
value: "marshall-islands",
},
{ code: "mr", continent: "Africa", label: "Mauritania", value: "mauritania" },
{ code: "mu", continent: "Africa", label: "Mauritius", value: "mauritius" },
{ code: "mx", continent: "North America", label: "Mexico", value: "mexico" },
{
code: "fm",
continent: "Oceania",
label: "Micronesia",
value: "micronesia",
},
{ code: "md", continent: "Europe", label: "Moldova", value: "moldova" },
{ code: "mc", continent: "Europe", label: "Monaco", value: "monaco" },
{ code: "mn", continent: "Asia", label: "Mongolia", value: "mongolia" },
{ code: "me", continent: "Europe", label: "Montenegro", value: "montenegro" },
{ code: "ma", continent: "Africa", label: "Morocco", value: "morocco" },
{ code: "mz", continent: "Africa", label: "Mozambique", value: "mozambique" },
{ code: "mm", continent: "Asia", label: "Myanmar", value: "myanmar" },
{ code: "na", continent: "Africa", label: "Namibia", value: "namibia" },
{ code: "nr", continent: "Oceania", label: "Nauru", value: "nauru" },
{ code: "np", continent: "Asia", label: "Nepal", value: "nepal" },
{
code: "nl",
continent: "Europe",
label: "Netherlands",
value: "netherlands",
},
{
code: "nz",
continent: "Oceania",
label: "New Zealand",
value: "new-zealand",
},
{
code: "ni",
continent: "North America",
label: "Nicaragua",
value: "nicaragua",
},
{ code: "ne", continent: "Africa", label: "Niger", value: "niger" },
{ code: "ng", continent: "Africa", label: "Nigeria", value: "nigeria" },
{ code: "kp", continent: "Asia", label: "North Korea", value: "north-korea" },
{
code: "mk",
continent: "Europe",
label: "North Macedonia",
value: "north-macedonia",
},
{ code: "no", continent: "Europe", label: "Norway", value: "norway" },
{ code: "om", continent: "Asia", label: "Oman", value: "oman" },
{ code: "pk", continent: "Asia", label: "Pakistan", value: "pakistan" },
{ code: "pw", continent: "Oceania", label: "Palau", value: "palau" },
{ code: "ps", continent: "Asia", label: "Palestine", value: "palestine" },
{ code: "pa", continent: "North America", label: "Panama", value: "panama" },
{
code: "pg",
continent: "Oceania",
label: "Papua New Guinea",
value: "papua-new-guinea",
},
{
code: "py",
continent: "South America",
label: "Paraguay",
value: "paraguay",
},
{ code: "pe", continent: "South America", label: "Peru", value: "peru" },
{ code: "ph", continent: "Asia", label: "Philippines", value: "philippines" },
{ code: "pl", continent: "Europe", label: "Poland", value: "poland" },
{ code: "pt", continent: "Europe", label: "Portugal", value: "portugal" },
{ code: "qa", continent: "Asia", label: "Qatar", value: "qatar" },
{ code: "ro", continent: "Europe", label: "Romania", value: "romania" },
{ code: "ru", continent: "Europe", label: "Russia", value: "russia" },
{ code: "rw", continent: "Africa", label: "Rwanda", value: "rwanda" },
{ code: "ws", continent: "Oceania", label: "Samoa", value: "samoa" },
{ code: "sm", continent: "Europe", label: "San Marino", value: "san-marino" },
{
code: "sa",
continent: "Asia",
label: "Saudi Arabia",
value: "saudi-arabia",
},
{ code: "sn", continent: "Africa", label: "Senegal", value: "senegal" },
{ code: "rs", continent: "Europe", label: "Serbia", value: "serbia" },
{ code: "sc", continent: "Africa", label: "Seychelles", value: "seychelles" },
{
code: "sl",
continent: "Africa",
label: "Sierra Leone",
value: "sierra-leone",
},
{ code: "sg", continent: "Asia", label: "Singapore", value: "singapore" },
{ code: "sk", continent: "Europe", label: "Slovakia", value: "slovakia" },
{ code: "si", continent: "Europe", label: "Slovenia", value: "slovenia" },
{
code: "sb",
continent: "Oceania",
label: "Solomon Islands",
value: "solomon-islands",
},
{ code: "so", continent: "Africa", label: "Somalia", value: "somalia" },
{
code: "za",
continent: "Africa",
label: "South Africa",
value: "south-africa",
},
{ code: "kr", continent: "Asia", label: "South Korea", value: "south-korea" },
{
code: "ss",
continent: "Africa",
label: "South Sudan",
value: "south-sudan",
},
{ code: "es", continent: "Europe", label: "Spain", value: "spain" },
{ code: "lk", continent: "Asia", label: "Sri Lanka", value: "sri-lanka" },
{ code: "sd", continent: "Africa", label: "Sudan", value: "sudan" },
{
code: "sr",
continent: "South America",
label: "Suriname",
value: "suriname",
},
{ code: "se", continent: "Europe", label: "Sweden", value: "sweden" },
{
code: "ch",
continent: "Europe",
label: "Switzerland",
value: "switzerland",
},
{ code: "sy", continent: "Asia", label: "Syria", value: "syria" },
{ code: "tw", continent: "Asia", label: "Taiwan", value: "taiwan" },
{ code: "tj", continent: "Asia", label: "Tajikistan", value: "tajikistan" },
{ code: "tz", continent: "Africa", label: "Tanzania", value: "tanzania" },
{ code: "th", continent: "Asia", label: "Thailand", value: "thailand" },
{ code: "tl", continent: "Asia", label: "Timor-Leste", value: "timor-leste" },
{ code: "tg", continent: "Africa", label: "Togo", value: "togo" },
{ code: "to", continent: "Oceania", label: "Tonga", value: "tonga" },
{
code: "tt",
continent: "North America",
label: "Trinidad and Tobago",
value: "trinidad-and-tobago",
},
{ code: "tn", continent: "Africa", label: "Tunisia", value: "tunisia" },
{ code: "tr", continent: "Asia", label: "Turkey", value: "turkey" },
{
code: "tm",
continent: "Asia",
label: "Turkmenistan",
value: "turkmenistan",
},
{ code: "tv", continent: "Oceania", label: "Tuvalu", value: "tuvalu" },
{ code: "ug", continent: "Africa", label: "Uganda", value: "uganda" },
{ code: "ua", continent: "Europe", label: "Ukraine", value: "ukraine" },
{
code: "ae",
continent: "Asia",
label: "United Arab Emirates",
value: "united-arab-emirates",
},
{
code: "gb",
continent: "Europe",
label: "United Kingdom",
value: "united-kingdom",
},
{
code: "us",
continent: "North America",
label: "United States",
value: "united-states",
},
{
code: "uy",
continent: "South America",
label: "Uruguay",
value: "uruguay",
},
{ code: "uz", continent: "Asia", label: "Uzbekistan", value: "uzbekistan" },
{ code: "vu", continent: "Oceania", label: "Vanuatu", value: "vanuatu" },
{
code: "va",
continent: "Europe",
label: "Vatican City",
value: "vatican-city",
},
{
code: "ve",
continent: "South America",
label: "Venezuela",
value: "venezuela",
},
{ code: "vn", continent: "Asia", label: "Vietnam", value: "vietnam" },
{ code: "ye", continent: "Asia", label: "Yemen", value: "yemen" },
{ code: "zm", continent: "Africa", label: "Zambia", value: "zambia" },
{ code: "zw", continent: "Africa", label: "Zimbabwe", value: "zimbabwe" },
];
export default function Particle() {
return (
<Combobox defaultValue={countries[0]} items={countries}>
<ComboboxTrigger
render={
<Button
className="w-full justify-between font-normal"
variant="outline"
/>
}
>
<ComboboxValue />
<ChevronsUpDownIcon className="-me-1!" />
</ComboboxTrigger>
<ComboboxPopup aria-label="Select country">
<div className="border-b p-2">
<ComboboxInput
className="rounded-md before:rounded-[calc(var(--radius-md)-1px)]"
placeholder="e.g. United Kingdom"
showTrigger={false}
startAddon={<SearchIcon />}
/>
</div>
<ComboboxEmpty>No countries found.</ComboboxEmpty>
<ComboboxList>
{(country: Country) => (
<ComboboxItem key={country.code} value={country}>
{country.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
With Select-like Button
Use SelectButton as a render prop on ComboboxTrigger to make the combobox trigger look like a select.
"use client";
import { SearchIcon } from "lucide-react";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxTrigger,
ComboboxValue,
} from "@/components/ui/combobox";
import { SelectButton } from "@/components/ui/select";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxTrigger render={<SelectButton />}>
<ComboboxValue placeholder="Select a fruit" />
</ComboboxTrigger>
<ComboboxPopup aria-label="Select a fruit">
<div className="border-b p-2">
<ComboboxInput
className="rounded-md before:rounded-[calc(var(--radius-md)-1px)]"
placeholder="Search fruits..."
showTrigger={false}
startAddon={<SearchIcon />}
/>
</div>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Form Integration
"use client";
import type { FormEvent } from "react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
const [loading, setLoading] = useState(false);
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const selectedItem = formData.get("item");
const itemValue =
items.find((item) => item.label === selectedItem)?.value || selectedItem;
setLoading(true);
await new Promise((r) => setTimeout(r, 800));
setLoading(false);
alert(`Favorite item: ${itemValue || ""}`);
};
return (
<Form className="flex w-full max-w-64 flex-col gap-4" onSubmit={onSubmit}>
<Field name="item">
<FieldLabel>Favorite item</FieldLabel>
<Combobox items={items} required>
<ComboboxInput placeholder="Select an item..." />
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
<FieldError>Please select a item.</FieldError>
</Field>
<Button loading={loading} type="submit">
Submit
</Button>
</Form>
);
}
Form Integration - Multiple
"use client";
import type { FormEvent } from "react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxValue,
} from "@/components/ui/combobox";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
const [loading, setLoading] = useState(false);
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const selectedItems = formData.getAll("items");
const itemValues = selectedItems.map(
(selectedItem) =>
items.find((item) => item.label === selectedItem)?.value ||
selectedItem,
);
setLoading(true);
await new Promise((r) => setTimeout(r, 800));
setLoading(false);
alert(`Favorite items: ${itemValues.join(", ") || ""}`);
};
return (
<Form className="flex w-full max-w-64 flex-col gap-4" onSubmit={onSubmit}>
<Field name="items">
<FieldLabel>Favorite items</FieldLabel>
<Combobox items={items} multiple required>
<ComboboxChips>
<ComboboxValue>
{(value: { value: string; label: string }[]) => (
<>
{value?.map((item) => (
<ComboboxChip aria-label={item.label} key={item.value}>
{item.label}
</ComboboxChip>
))}
<ComboboxChipsInput
placeholder={value.length > 0 ? undefined : "Select items…"}
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
<FieldError>Please select at least one item.</FieldError>
</Field>
<Button loading={loading} type="submit">
Submit
</Button>
</Form>
);
}
On This Page