Combobox
Searchable picker for larger option lists with keyboard navigation support.
01 Live Demo
expand_more
02 Code Snippet
src/ui/Combobox.tsx
import { Combobox } from "@/ui/Combobox"; <Combobox.Root value={value} onValueChange={setValue} options={[ { label: "React", value: "react" }, { label: "Vue", value: "vue" }, { label: "Svelte", value: "svelte" }, ]} placeholder="Search framework..." />
03 Copy-Paste (Single File)
Combobox.tsx
import { useMemo, useState } from "react"; type Option = { label: string; value: string }; function ComboboxRoot({ options, value, onValueChange, placeholder = "Search..." }: { options: Option[]; value?: string; onValueChange?: (value: string) => void; placeholder?: string }) { const [query, setQuery] = useState(""); const [open, setOpen] = useState(false); const filtered = useMemo(() => options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())), [options, query]); return ( <div className="relative"> <input value={query} onChange={(event) => { setQuery(event.target.value); setOpen(true); }} onFocus={() => setOpen(true)} placeholder={placeholder} className="h-10 w-full rounded-lg border border-slate-200 px-3.5 text-sm" /> {open && ( <div className="absolute z-40 mt-2 w-full rounded-xl border border-slate-200 bg-white p-1 shadow-xl"> {filtered.map((option) => ( <button key={option.value} className="w-full rounded-lg px-3 py-2 text-left text-sm hover:bg-slate-50" onClick={() => { onValueChange?.(option.value); setQuery(option.label); setOpen(false); }}> {option.label} {value === option.value ? "✓" : ""} </button> ))} </div> )} </div> ); } type ComboboxCompound = typeof ComboboxRoot & { Root: typeof ComboboxRoot }; export const Combobox = Object.assign(ComboboxRoot, { Root: ComboboxRoot }) as ComboboxCompound;