Combobox
Autocomplete input with a list of suggestions.
The Combobox component is built on top of Kobalte Combobox, which provides the accessible autocomplete primitive and keyboard navigation.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxDemo() { return ( <Combobox options={frameworks} placeholder="Select a framework..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select a framework..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Installation
Usage
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];<Combobox options={frameworks} placeholder="Select a framework..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )}> <ComboboxInput placeholder="Select a framework..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent></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 └── ComboboxEmptyWith 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 └── ComboboxSectionLabelCustom Items
Use optionValue and optionTextValue when your options are objects.
type Framework = { label: string; value: string;};
const frameworks: Framework[] = [ { label: "Next.js", value: "next" }, { label: "SvelteKit", value: "sveltekit" }, { label: "Nuxt", value: "nuxt" },];
<Combobox options={frameworks} optionValue="value" optionTextValue="label" placeholder="Select a framework..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue.label}</ComboboxItem> )}> <ComboboxInput placeholder="Select a framework..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent></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.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
<Combobox options={frameworks} placeholder="Select frameworks..." multiple defaultValue={[frameworks[0]]} itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )}> <ComboboxInput placeholder="Select frameworks..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent></Combobox>Basic
A simple combobox with a list of frameworks.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxBasic() { return ( <Combobox options={frameworks} placeholder="Select a framework..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select a framework..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Multiple
A combobox with multiple selection using multiple.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxMultiple() { return ( <Combobox<(typeof frameworks)[number]> options={frameworks} placeholder="Select frameworks..." multiple defaultValue={[frameworks[0]]} itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select frameworks..." /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Clear Button
Use the showClear prop to show a clear button.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxClear() { return ( <Combobox options={frameworks} placeholder="Select a framework..." defaultValue={frameworks[0]} itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select a framework..." showClear /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Groups
Use optionGroupChildren with a sectionComponent rendering ComboboxSection, ComboboxSectionLabel, and ComboboxSeparator to group items.
import { Show } from "solid-js";import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxSectionLabel, ComboboxSeparator,} from "~/components/ui/combobox";
type TimezoneGroup = { label: string; options: string[];};
const timezones: TimezoneGroup[] = [ { label: "Americas", options: [ "(GMT-5) New York", "(GMT-8) Los Angeles", "(GMT-6) Chicago", "(GMT-5) Toronto", "(GMT-8) Vancouver", "(GMT-3) São Paulo", ], }, { label: "Europe", options: [ "(GMT+0) London", "(GMT+1) Paris", "(GMT+1) Berlin", "(GMT+1) Rome", "(GMT+1) Madrid", "(GMT+1) Amsterdam", ], }, { label: "Asia/Pacific", options: [ "(GMT+9) Tokyo", "(GMT+8) Shanghai", "(GMT+8) Singapore", "(GMT+4) Dubai", "(GMT+11) Sydney", "(GMT+9) Seoul", ], },];
export default function ComboboxGroups() { return ( <Combobox<string, TimezoneGroup> options={timezones} optionValue={(option) => option} optionTextValue={(option) => option} optionGroupChildren="options" placeholder="Select a timezone..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} sectionComponent={(props) => ( <> <Show when={props.section.index !== 0}> <ComboboxSeparator /> </Show> <ComboboxSection> <ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel> </ComboboxSection> </> )} > <ComboboxInput placeholder="Select a timezone..." /> <ComboboxContent> <ComboboxEmpty>No timezones found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Custom Items
You can render a custom component inside ComboboxItem via itemComponent.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";import { Item, ItemContent, ItemDescription, ItemTitle } from "~/components/ui/item";
const countries = [ { 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 default function ComboboxCustom() { return ( <Combobox<(typeof countries)[number]> options={countries} optionValue="value" optionTextValue="label" placeholder="Search countries..." itemComponent={(props) => ( <ComboboxItem item={props.item}> <Item size="xs" class="p-0"> <ItemContent> <ItemTitle class="whitespace-nowrap">{props.item.rawValue.label}</ItemTitle> <ItemDescription> {props.item.rawValue.continent} ({props.item.rawValue.code}) </ItemDescription> </ItemContent> </Item> </ComboboxItem> )} > <ComboboxInput placeholder="Search countries..." /> <ComboboxContent> <ComboboxEmpty>No countries found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Invalid
Use the validationState="invalid" prop to make the combobox invalid.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxInvalid() { return ( <Combobox options={frameworks} placeholder="Select a framework..." validationState="invalid" itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select a framework..." aria-invalid="true" /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Disabled
Use the disabled prop to disable the combobox.
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem,} from "~/components/ui/combobox";
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"];
export default function ComboboxDisabled() { return ( <Combobox options={frameworks} placeholder="Select a framework..." disabled itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} > <ComboboxInput placeholder="Select a framework..." disabled /> <ComboboxContent> <ComboboxEmpty>No frameworks found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Popup
Use ComboboxTrigger to open a combobox from a button instead of a text input.
import { createSignal } from "solid-js";import { Button } from "~/components/ui/button";import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxItem, ComboboxTrigger,} from "~/components/ui/combobox";
const countries = [ { code: "ar", value: "argentina", label: "Argentina" }, { code: "au", value: "australia", label: "Australia" }, { code: "br", value: "brazil", label: "Brazil" }, { code: "ca", value: "canada", label: "Canada" }, { code: "cn", value: "china", label: "China" }, { code: "fr", value: "france", label: "France" }, { code: "de", value: "germany", label: "Germany" }, { code: "jp", value: "japan", label: "Japan" }, { code: "gb", value: "united-kingdom", label: "United Kingdom" }, { code: "us", value: "united-states", label: "United States" },];
export default function ComboboxPopup() { const [value, setValue] = createSignal<(typeof countries)[number] | null>(null);
return ( <Combobox<(typeof countries)[number]> options={countries} value={value()} onChange={setValue} optionValue="value" optionTextValue="label" placeholder="Select country" itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue.label}</ComboboxItem> )} > <ComboboxTrigger as={Button} variant="outline" class="w-64 justify-between font-normal"> {value()?.label ?? "Select country"} </ComboboxTrigger> <ComboboxContent> <ComboboxEmpty>No countries found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}Input Group
Add an addon to the combobox by placing InputGroupAddon inside ComboboxInput.
import { GlobeIcon } from "lucide-solid";import { Show } from "solid-js";import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxSectionLabel, ComboboxSeparator,} from "~/components/ui/combobox";import { InputGroupAddon } from "~/components/ui/input-group";
type TimezoneGroup = { label: string; options: string[];};
const timezones: TimezoneGroup[] = [ { label: "Americas", options: [ "(GMT-5) New York", "(GMT-8) Los Angeles", "(GMT-6) Chicago", "(GMT-5) Toronto", "(GMT-8) Vancouver", "(GMT-3) São Paulo", ], }, { label: "Europe", options: [ "(GMT+0) London", "(GMT+1) Paris", "(GMT+1) Berlin", "(GMT+1) Rome", "(GMT+1) Madrid", "(GMT+1) Amsterdam", ], }, { label: "Asia/Pacific", options: [ "(GMT+9) Tokyo", "(GMT+8) Shanghai", "(GMT+8) Singapore", "(GMT+4) Dubai", "(GMT+11) Sydney", "(GMT+9) Seoul", ], },];
export default function ComboboxInputGroup() { return ( <Combobox<string, TimezoneGroup> options={timezones} optionValue={(option) => option} optionTextValue={(option) => option} optionGroupChildren="options" placeholder="Select a timezone..." itemComponent={(props) => ( <ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem> )} sectionComponent={(props) => ( <> <Show when={props.section.index !== 0}> <ComboboxSeparator /> </Show> <ComboboxSection> <ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel> </ComboboxSection> </> )} > <ComboboxInput placeholder="Select a timezone..."> <InputGroupAddon> <GlobeIcon class="size-4" /> </InputGroupAddon> </ComboboxInput> <ComboboxContent class="w-60"> <ComboboxEmpty>No timezones found.</ComboboxEmpty> </ComboboxContent> </Combobox> );}API Reference
See the Kobalte Combobox API reference for primitive props, keyboard behavior, and accessibility details.