ZaidanHomeDocsComponentsBlocksChartsTypesetCreate

Command Palette

Search for a command to run...

GitHub
New
Sections
  • Introduction
  • Components
  • Blocks
  • Installation
  • Customization
  • Dark Mode
  • Typeset
  • Zaidan Skills
  • FAQ
  • Roadmap
  • Changelog
Installation
  • Astro
  • Manual
  • Solid Start
  • TanStack Router
  • TanStack Start
  • Vite
Blocks
  • Data Grid
  • Event Calendar
  • Filters
  • Gantt
  • Image Crop
  • Kanban
  • Message Scroller
  • Questionnaire
  • Sortable
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Attachment
  • Avatar
  • Badge
  • Breadcrumb
  • Bubble
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Dialog
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Marker
  • Menubar
  • Message
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip

Combobox

Autocomplete input with a list of suggestions.

Kobalte
Kobalte

The Combobox component is built on top of Kobalte Combobox, which provides the accessible autocomplete primitive and keyboard navigation.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxDemo() {
12
return (
13
<Combobox
14
options={frameworks}
15
placeholder="Select a framework..."
16
itemComponent={(props) => (
17
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
18
)}
19
>
20
<ComboboxInput placeholder="Select a framework..." />
21
<ComboboxContent>
22
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
23
</ComboboxContent>
24
</Combobox>
25
);
26
}

Installation

pnpm dlx shadcn@latest add @zaidan/combobox
npx shadcn@latest add @zaidan/combobox
yarn dlx shadcn@latest add @zaidan/combobox
bunx --bun shadcn@latest add @zaidan/combobox

Usage

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
1
<Combobox
2
options={frameworks}
3
placeholder="Select a framework..."
4
itemComponent={(props) => (
5
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
6
)}
7
>
8
<ComboboxInput placeholder="Select a framework..." />
9
<ComboboxContent>
10
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
11
</ComboboxContent>
12
</Combobox>

See the Kobalte Combobox documentation for primitive-level options, accessibility, and keyboard behavior.

Composition

Simple

A single-line input and a flat list rendered from options via itemComponent (see Basic).

Combobox
├── ComboboxInput
└── ComboboxContent
└── ComboboxEmpty

With Groups

Group options with optionGroupChildren, and render a section heading (and an optional separator) from sectionComponent (see Groups).

Combobox
├── ComboboxInput
└── ComboboxContent
└── ComboboxEmpty
sectionComponent renders, per group:
├── ComboboxSeparator (optional, skipped for the first group)
└── ComboboxSection
└── ComboboxSectionLabel

Custom Items

Use optionValue and optionTextValue when your options are objects.

1
type Framework = {
2
label: string;
3
value: string;
4
};
5
6
const frameworks: Framework[] = [
7
{ label: "Next.js", value: "next" },
8
{ label: "SvelteKit", value: "sveltekit" },
9
{ label: "Nuxt", value: "nuxt" },
10
];
11
12
<Combobox
13
options={frameworks}
14
optionValue="value"
15
optionTextValue="label"
16
placeholder="Select a framework..."
17
itemComponent={(props) => (
18
<ComboboxItem item={props.item}>{props.item.rawValue.label}</ComboboxItem>
19
)}
20
>
21
<ComboboxInput placeholder="Select a framework..." />
22
<ComboboxContent>
23
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
24
</ComboboxContent>
25
</Combobox>

Multiple Selection

Use multiple (with a T[] value/defaultValue) for multi-select behavior. The input text reflects the selection the same way single-select does.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
<Combobox
10
options={frameworks}
11
placeholder="Select frameworks..."
12
multiple
13
defaultValue={[frameworks[0]]}
14
itemComponent={(props) => (
15
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
16
)}
17
>
18
<ComboboxInput placeholder="Select frameworks..." />
19
<ComboboxContent>
20
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
21
</ComboboxContent>
22
</Combobox>

Basic

A simple combobox with a list of frameworks.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxBasic() {
12
return (
13
<Combobox
14
options={frameworks}
15
placeholder="Select a framework..."
16
itemComponent={(props) => (
17
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
18
)}
19
>
20
<ComboboxInput placeholder="Select a framework..." />
21
<ComboboxContent>
22
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
23
</ComboboxContent>
24
</Combobox>
25
);
26
}

Multiple

A combobox with multiple selection using multiple.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxMultiple() {
12
return (
13
<Combobox<(typeof frameworks)[number]>
14
options={frameworks}
15
placeholder="Select frameworks..."
16
multiple
17
defaultValue={[frameworks[0]]}
18
itemComponent={(props) => (
19
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
20
)}
21
>
22
<ComboboxInput placeholder="Select frameworks..." />
23
<ComboboxContent>
24
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
25
</ComboboxContent>
26
</Combobox>
27
);
28
}

Clear Button

Use the showClear prop to show a clear button.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxClear() {
12
return (
13
<Combobox
14
options={frameworks}
15
placeholder="Select a framework..."
16
defaultValue={frameworks[0]}
17
itemComponent={(props) => (
18
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
19
)}
20
>
21
<ComboboxInput placeholder="Select a framework..." showClear />
22
<ComboboxContent>
23
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
24
</ComboboxContent>
25
</Combobox>
26
);
27
}

Groups

Use optionGroupChildren with a sectionComponent rendering ComboboxSection, ComboboxSectionLabel, and ComboboxSeparator to group items.

1
import { Show } from "solid-js";
2
import {
3
Combobox,
4
ComboboxContent,
5
ComboboxEmpty,
6
ComboboxInput,
7
ComboboxItem,
8
ComboboxSection,
9
ComboboxSectionLabel,
10
ComboboxSeparator,
11
} from "~/components/ui/combobox";
12
13
type TimezoneGroup = {
14
label: string;
15
options: string[];
16
};
17
18
const timezones: TimezoneGroup[] = [
19
{
20
label: "Americas",
21
options: [
22
"(GMT-5) New York",
23
"(GMT-8) Los Angeles",
24
"(GMT-6) Chicago",
25
"(GMT-5) Toronto",
26
"(GMT-8) Vancouver",
27
"(GMT-3) São Paulo",
28
],
29
},
30
{
31
label: "Europe",
32
options: [
33
"(GMT+0) London",
34
"(GMT+1) Paris",
35
"(GMT+1) Berlin",
36
"(GMT+1) Rome",
37
"(GMT+1) Madrid",
38
"(GMT+1) Amsterdam",
39
],
40
},
41
{
42
label: "Asia/Pacific",
43
options: [
44
"(GMT+9) Tokyo",
45
"(GMT+8) Shanghai",
46
"(GMT+8) Singapore",
47
"(GMT+4) Dubai",
48
"(GMT+11) Sydney",
49
"(GMT+9) Seoul",
50
],
51
},
52
];
53
54
export default function ComboboxGroups() {
55
return (
56
<Combobox<string, TimezoneGroup>
57
options={timezones}
58
optionValue={(option) => option}
59
optionTextValue={(option) => option}
60
optionGroupChildren="options"
61
placeholder="Select a timezone..."
62
itemComponent={(props) => (
63
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
64
)}
65
sectionComponent={(props) => (
66
<>
67
<Show when={props.section.index !== 0}>
68
<ComboboxSeparator />
69
</Show>
70
<ComboboxSection>
71
<ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel>
72
</ComboboxSection>
73
</>
74
)}
75
>
76
<ComboboxInput placeholder="Select a timezone..." />
77
<ComboboxContent>
78
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
79
</ComboboxContent>
80
</Combobox>
81
);
82
}

Custom Items

You can render a custom component inside ComboboxItem via itemComponent.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
import { Item, ItemContent, ItemDescription, ItemTitle } from "~/components/ui/item";
9
10
const countries = [
11
{ code: "ar", value: "argentina", label: "Argentina", continent: "South America" },
12
{ code: "au", value: "australia", label: "Australia", continent: "Oceania" },
13
{ code: "br", value: "brazil", label: "Brazil", continent: "South America" },
14
{ code: "ca", value: "canada", label: "Canada", continent: "North America" },
15
{ code: "cn", value: "china", label: "China", continent: "Asia" },
16
{ code: "co", value: "colombia", label: "Colombia", continent: "South America" },
17
{ code: "eg", value: "egypt", label: "Egypt", continent: "Africa" },
18
{ code: "fr", value: "france", label: "France", continent: "Europe" },
19
{ code: "de", value: "germany", label: "Germany", continent: "Europe" },
20
{ code: "it", value: "italy", label: "Italy", continent: "Europe" },
21
{ code: "jp", value: "japan", label: "Japan", continent: "Asia" },
22
{ code: "ke", value: "kenya", label: "Kenya", continent: "Africa" },
23
{ code: "mx", value: "mexico", label: "Mexico", continent: "North America" },
24
{ code: "nz", value: "new-zealand", label: "New Zealand", continent: "Oceania" },
25
{ code: "ng", value: "nigeria", label: "Nigeria", continent: "Africa" },
26
{ code: "za", value: "south-africa", label: "South Africa", continent: "Africa" },
27
{ code: "kr", value: "south-korea", label: "South Korea", continent: "Asia" },
28
{ code: "gb", value: "united-kingdom", label: "United Kingdom", continent: "Europe" },
29
{ code: "us", value: "united-states", label: "United States", continent: "North America" },
30
];
31
32
export default function ComboboxCustom() {
33
return (
34
<Combobox<(typeof countries)[number]>
35
options={countries}
36
optionValue="value"
37
optionTextValue="label"
38
placeholder="Search countries..."
39
itemComponent={(props) => (
40
<ComboboxItem item={props.item}>
41
<Item size="xs" class="p-0">
42
<ItemContent>
43
<ItemTitle class="whitespace-nowrap">{props.item.rawValue.label}</ItemTitle>
44
<ItemDescription>
45
{props.item.rawValue.continent} ({props.item.rawValue.code})
46
</ItemDescription>
47
</ItemContent>
48
</Item>
49
</ComboboxItem>
50
)}
51
>
52
<ComboboxInput placeholder="Search countries..." />
53
<ComboboxContent>
54
<ComboboxEmpty>No countries found.</ComboboxEmpty>
55
</ComboboxContent>
56
</Combobox>
57
);
58
}

Invalid

Use the validationState="invalid" prop to make the combobox invalid.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxInvalid() {
12
return (
13
<Combobox
14
options={frameworks}
15
placeholder="Select a framework..."
16
validationState="invalid"
17
itemComponent={(props) => (
18
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
19
)}
20
>
21
<ComboboxInput placeholder="Select a framework..." aria-invalid="true" />
22
<ComboboxContent>
23
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
24
</ComboboxContent>
25
</Combobox>
26
);
27
}

Disabled

Use the disabled prop to disable the combobox.

1
import {
2
Combobox,
3
ComboboxContent,
4
ComboboxEmpty,
5
ComboboxInput,
6
ComboboxItem,
7
} from "~/components/ui/combobox";
8
9
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
10
11
export default function ComboboxDisabled() {
12
return (
13
<Combobox
14
options={frameworks}
15
placeholder="Select a framework..."
16
disabled
17
itemComponent={(props) => (
18
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
19
)}
20
>
21
<ComboboxInput placeholder="Select a framework..." disabled />
22
<ComboboxContent>
23
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
24
</ComboboxContent>
25
</Combobox>
26
);
27
}

Popup

Use ComboboxTrigger to open a combobox from a button instead of a text input.

1
import { createSignal } from "solid-js";
2
import { Button } from "~/components/ui/button";
3
import {
4
Combobox,
5
ComboboxContent,
6
ComboboxEmpty,
7
ComboboxItem,
8
ComboboxTrigger,
9
} from "~/components/ui/combobox";
10
11
const countries = [
12
{ code: "ar", value: "argentina", label: "Argentina" },
13
{ code: "au", value: "australia", label: "Australia" },
14
{ code: "br", value: "brazil", label: "Brazil" },
15
{ code: "ca", value: "canada", label: "Canada" },
16
{ code: "cn", value: "china", label: "China" },
17
{ code: "fr", value: "france", label: "France" },
18
{ code: "de", value: "germany", label: "Germany" },
19
{ code: "jp", value: "japan", label: "Japan" },
20
{ code: "gb", value: "united-kingdom", label: "United Kingdom" },
21
{ code: "us", value: "united-states", label: "United States" },
22
];
23
24
export default function ComboboxPopup() {
25
const [value, setValue] = createSignal<(typeof countries)[number] | null>(null);
26
27
return (
28
<Combobox<(typeof countries)[number]>
29
options={countries}
30
value={value()}
31
onChange={setValue}
32
optionValue="value"
33
optionTextValue="label"
34
placeholder="Select country"
35
itemComponent={(props) => (
36
<ComboboxItem item={props.item}>{props.item.rawValue.label}</ComboboxItem>
37
)}
38
>
39
<ComboboxTrigger as={Button} variant="outline" class="w-64 justify-between font-normal">
40
{value()?.label ?? "Select country"}
41
</ComboboxTrigger>
42
<ComboboxContent>
43
<ComboboxEmpty>No countries found.</ComboboxEmpty>
44
</ComboboxContent>
45
</Combobox>
46
);
47
}

Input Group

Add an addon to the combobox by placing InputGroupAddon inside ComboboxInput.

1
import { GlobeIcon } from "lucide-solid";
2
import { Show } from "solid-js";
3
import {
4
Combobox,
5
ComboboxContent,
6
ComboboxEmpty,
7
ComboboxInput,
8
ComboboxItem,
9
ComboboxSection,
10
ComboboxSectionLabel,
11
ComboboxSeparator,
12
} from "~/components/ui/combobox";
13
import { InputGroupAddon } from "~/components/ui/input-group";
14
15
type TimezoneGroup = {
16
label: string;
17
options: string[];
18
};
19
20
const timezones: TimezoneGroup[] = [
21
{
22
label: "Americas",
23
options: [
24
"(GMT-5) New York",
25
"(GMT-8) Los Angeles",
26
"(GMT-6) Chicago",
27
"(GMT-5) Toronto",
28
"(GMT-8) Vancouver",
29
"(GMT-3) São Paulo",
30
],
31
},
32
{
33
label: "Europe",
34
options: [
35
"(GMT+0) London",
36
"(GMT+1) Paris",
37
"(GMT+1) Berlin",
38
"(GMT+1) Rome",
39
"(GMT+1) Madrid",
40
"(GMT+1) Amsterdam",
41
],
42
},
43
{
44
label: "Asia/Pacific",
45
options: [
46
"(GMT+9) Tokyo",
47
"(GMT+8) Shanghai",
48
"(GMT+8) Singapore",
49
"(GMT+4) Dubai",
50
"(GMT+11) Sydney",
51
"(GMT+9) Seoul",
52
],
53
},
54
];
55
56
export default function ComboboxInputGroup() {
57
return (
58
<Combobox<string, TimezoneGroup>
59
options={timezones}
60
optionValue={(option) => option}
61
optionTextValue={(option) => option}
62
optionGroupChildren="options"
63
placeholder="Select a timezone..."
64
itemComponent={(props) => (
65
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
66
)}
67
sectionComponent={(props) => (
68
<>
69
<Show when={props.section.index !== 0}>
70
<ComboboxSeparator />
71
</Show>
72
<ComboboxSection>
73
<ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel>
74
</ComboboxSection>
75
</>
76
)}
77
>
78
<ComboboxInput placeholder="Select a timezone...">
79
<InputGroupAddon>
80
<GlobeIcon class="size-4" />
81
</InputGroupAddon>
82
</ComboboxInput>
83
<ComboboxContent class="w-60">
84
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
85
</ComboboxContent>
86
</Combobox>
87
);
88
}

API Reference

See the Kobalte Combobox API reference for primitive props, keyboard behavior, and accessibility details.

On This Page

  • Installation
  • Usage
  • Composition
    • Simple
    • With Groups
  • Custom Items
  • Multiple Selection
  • Basic
  • Multiple
  • Clear Button
  • Groups
  • Custom Items
  • Invalid
  • Disabled
  • Popup
  • Input Group
  • API Reference
Built by Kevin Abatan. The source code is available on GitHub.