Combobox

A searchable select built from cmdk and Radix Popover. Compose it from eight primitive parts — trigger, content, input, list, item, empty, and group — for full control over layout and behavior.

  • Built on cmdk + Radix UI Popover — no extra library required
  • Fully composable: eight named sub-components
  • Single and multi-select patterns via the selected prop on ComboboxItem
  • Searchable with built-in keyboard navigation
  • Group items with ComboboxGroup and a heading label
  • Animates open/close with Tailwind data-state variants

import { Combobox }from "@aetherstack/ui"

combobox.tsx
"use client"

import { useState } from "react"
import { ChevronsUpDown } from "lucide-react"
import {
  Combobox, ComboboxTrigger, ComboboxContent,
  ComboboxInput, ComboboxList, ComboboxItem, ComboboxEmpty,
} from "@/components/ui/combobox"
import { Button } from "@/components/ui/button"

const fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]

export function ComboboxDemo() {
  const [open, setOpen] = useState(false)
  const [value, setValue] = useState("")

  return (
    <Combobox open={open} onOpenChange={setOpen}>
      <ComboboxTrigger asChild>
        <Button variant="outline" className="w-48 justify-between">
          {value || "Select a fruit…"}
          <ChevronsUpDown className="opacity-50" />
        </Button>
      </ComboboxTrigger>
      <ComboboxContent>
        <ComboboxInput placeholder="Search fruits…" />
        <ComboboxList>
          <ComboboxEmpty>No fruit found.</ComboboxEmpty>
          {fruits.map((fruit) => (
            <ComboboxItem
              key={fruit}
              value={fruit}
              selected={value === fruit}
              onSelect={() => {
                setValue(fruit === value ? "" : fruit)
                setOpen(false)
              }}
            >
              {fruit}
            </ComboboxItem>
          ))}
        </ComboboxList>
      </ComboboxContent>
    </Combobox>
  )
}

Usage

Basic select

A single-select combobox with live filtering.

With groups

Use ComboboxGroup with a heading to visually separate items into categories.

Multi-select

Keep the popover open on select and track an array of selected values.

Props

PropTypeDefaultDescription
ComboboxPopoverPrimitive.RootRoot wrapper — manages open/closed state. Accepts open, onOpenChange, defaultOpen.
ComboboxTriggerPopoverPrimitive.TriggerThe element that toggles the combobox open. Use asChild to render as a Button.
ComboboxContentReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>Popover panel containing the Command root. Renders in a portal.
ComboboxInputReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>The search input — filters the list in real time.
ComboboxListReact.ComponentPropsWithoutRef<typeof CommandPrimitive.List>Scrollable list container. Max height 300px by default.
ComboboxItemReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> & { selected?: boolean }A single selectable option. Set selected={true} to show a checkmark.
ComboboxEmptyReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>Rendered when no items match the current search input.
ComboboxGroupReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>Groups items under a labeled heading. Pass heading prop for the group label.

* Required props

Accessibility

  • Built on cmdk which implements the ARIA combobox pattern with listbox role.
  • Keyboard navigation: arrow keys move between items, Enter selects, Escape closes.
  • Search input is automatically focused when the popover opens.
  • Selected state is communicated via aria-selected on each item.
  • Portal rendering ensures the listbox is not clipped by overflow-hidden containers.