Shadcn Combobox
The shadcn/ui combobox is a searchable single-select built by combining a Popover, a Command menu, and a Button trigger, styled with Tailwind CSS v4. Because you compose it, you control the trigger label, filtering, and empty state. Comboboxes handle long option lists in filters and forms across ShadcnStore blocks.
Key features
- Type-to-filter search over a long option list.
- Single selection with a custom trigger label.
- Keyboard navigation from the Command menu.
- Works with static, dynamic, or async options.
- Composed from Popover + Command + Button.
Installation
Add the pieces it composes:
npx shadcn@latest add popover command buttonUsage
"use client"
import { useState } from "react"
import { Check, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover"
import {
Command,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
} from "@/components/ui/command"
const frameworks = [
{ value: "next", label: "Next.js" },
{ value: "sveltekit", label: "SvelteKit" },
{ value: "astro", label: "Astro" },
]
export function Combobox() {
const [open, setOpen] = useState(false)
const [value, setValue] = useState("")
const selected = frameworks.find((f) => f.value === value)
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger
render={
<Button variant="outline" role="combobox" aria-expanded={open} />
}
>
{selected ? selected.label : "Select framework…"}
<ChevronsUpDown className="ml-2 size-4 opacity-50" />
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search framework…" />
<CommandList>
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((f) => (
<CommandItem
key={f.value}
value={f.value}
onSelect={(v) => {
setValue(v === value ? "" : v)
setOpen(false)
}}
>
<Check
className={value === f.value ? "mr-2 size-4" : "mr-2 size-4 opacity-0"}
/>
{f.label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
)
}Composition
The combobox composes Popover and Command. Use render on PopoverTrigger to style the trigger as a Button:
<PopoverTrigger render={<Button variant="outline" role="combobox" aria-expanded={open} />}>
{selected ? selected.label : "Select framework…"}
</PopoverTrigger>Accessibility
- Give the trigger
role="combobox"and reflect the open state witharia-expanded. - The Command input drives an accessible list; keep option labels unique.
- Show a clear empty state and keep the selected value visible in the trigger.
When to use the Combobox
Use a combobox when the user picks one value from a long or searchable list: a country, a repository, a user, or a framework. For a short, fixed list use a Select. For choosing among a few always-visible options, use a Radio Group.
Used in these blocks
- Category filters: searchable filters.
- Checkout forms: country and address selects.
- Apps: assignee and tag pickers.
Related components
The combobox is built from Popover, Command, and Button, and usually lives inside a Form. For a short fixed list use a Select.
FAQ
What is the shadcn combobox?
The combobox is a searchable single-select built by combining a Popover, a Command menu, and a Button trigger, ideal for long option lists.
Is the combobox a single component?
No. shadcn provides the Popover and Command pieces and a guide to compose them, so you control the trigger and filtering.
What is the difference between Combobox and Select?
Combobox adds type-to-filter search and suits long or async lists. Select is a simpler menu for short, fixed option sets.
How do I load combobox options asynchronously?
Fetch options into state and render them as CommandItems; the Command menu filters whatever you provide.