Combobox
A text field that suggests as you type: Input's well with a clear button and a chevron, over Select's panel and rows.
Install
# once per project: where @zzzui items come frompnpm dlx shadcn@latest registry add @zzzui=https://zzzui.catforest.dev/r/{name}.jsonpnpm dlx shadcn@latest add @zzzui/comboboxExamples
Pick a district
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList,} from "@/components/zero/combobox";const districts = [ { value: "harbor", label: "Harbor" }, { value: "rail-yards", label: "Rail yards" }, { value: "old-market", label: "Old market" }, { value: "canal-docks", label: "Canal docks" }, { value: "tower-9", label: "Tower 9" }, { value: "north-gate", label: "North gate" },];export default function ComboboxDistrict() { return ( <div className="w-full max-w-xs"> <Combobox items={districts}> <ComboboxInput placeholder="Pick a district" aria-label="District" /> <ComboboxContent> <ComboboxEmpty>No district by that name.</ComboboxEmpty> <ComboboxList> {(item: (typeof districts)[number]) => ( <ComboboxItem key={item.value} value={item}> {item.label} </ComboboxItem> )} </ComboboxList> </ComboboxContent> </Combobox> </div> );}Several districts, as chips
Harbor
import { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxContent, ComboboxEmpty, ComboboxItem, ComboboxList, ComboboxValue,} from "@/components/zero/combobox";type District = { value: string; label: string };const districts: District[] = [ { value: "harbor", label: "Harbor" }, { value: "rail-yards", label: "Rail yards" }, { value: "old-market", label: "Old market" }, { value: "canal-docks", label: "Canal docks" }, { value: "tower-9", label: "Tower 9" }, { value: "north-gate", label: "North gate" },];export default function ComboboxDistricts() { return ( <div className="w-full max-w-sm"> <Combobox items={districts} multiple defaultValue={[districts[0]]}> <ComboboxChips> <ComboboxValue> {(value: District[]) => ( <> {value.map((district) => ( <ComboboxChip key={district.value}> {district.label} </ComboboxChip> ))} <ComboboxChipsInput aria-label="Districts" placeholder={value.length > 0 ? "" : "Pick districts"} /> </> )} </ComboboxValue> </ComboboxChips> <ComboboxContent> <ComboboxEmpty>No district by that name.</ComboboxEmpty> <ComboboxList> {(item: District) => ( <ComboboxItem key={item.value} value={item}> {item.label} </ComboboxItem> )} </ComboboxList> </ComboboxContent> </Combobox> </div> );}Behaviour
Typing filters the list; the highlighted row fills with the accent and the chosen one carries the slanted mark. Pass the items to Combobox and render each from ComboboxList's function child.
With multiple, the chosen items sit in the field as small slabs (ComboboxChips, ComboboxChip, ComboboxChipsInput), each with a button that takes it out; the field wraps them, so it is Textarea's square well. Backspace at the start of the text takes out the last one.
Props
Combobox
| Prop | Type | Default | Description |
|---|---|---|---|
| items | Item[] | — | What to suggest; each item needs a label. |
| value / onValueChange | Item | null | — | The chosen item, controlled. |
Also takes every prop of Base UI's Combobox.Root.
ComboboxInput
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "sm" | "md" | "lg" | "md" | Input's heights. |
| cut | "end" | "start" | "both" | "none" | "end" | Which edges are cut on the slant. |
| showClear | boolean | true | The clear button. |
ComboboxContent, ComboboxList, ComboboxItem, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxChips, ComboboxChip, ComboboxChipsInput
Also takes every prop of Base UI's Combobox.Popup.