v1.0

Combobox

Text input that filters a list as you type and commits one value, with optional off-list custom values.

Pro

Description

Combobox is built on React Aria's ComboBox: the trigger is a text input, so you type to filter the list, arrow through matches, and commit one value. It composes a Combobox.Input and a Combobox.Popover surface holding Combobox.Item rows, with optional Combobox.Section, Combobox.Label, and Combobox.Footer slots. The list, items, and section headings are the same surface as Dropdown and Select, so a row looks identical across all three. size is set on the root and cascades through context to every item, label, and icon.

Reach for it when the set of options is long enough that scrolling is slower than typing, or when the value might not be in the list at all. With allowsCustomValue the field accepts a value you type that no option matches, which is the one thing a Select cannot do. It binds to a Field like any other control and inherits its size and invalid/disabled/loading state.

The free tier covers the input trigger, plain Combobox.Item rows, the empty state, custom values, and the three sizes. Smart items (a leading media slot, a secondary description, a trailing slot) and grouped Combobox.Section + Combobox.Label are Pro, matching the Dropdown tiers. Do not use a combobox when the choices are few and always visible (use Select or a Radio Group), or for a list of commands rather than values (use Dropdown).

Installation

pnpm dlx @create-ui/cli add combobox

Anatomy

<Combobox>
  <Combobox.Input />
  <Combobox.Popover>
    <Combobox.Section>
      <Combobox.Label />
      <Combobox.Item />
      <Combobox.Separator />
    </Combobox.Section>
    <Combobox.Footer />
  </Combobox.Popover>
</Combobox>

Usage

import { Combobox } from "@/components/ui/combobox"
<Combobox aria-label="Framework" allowsEmptyCollection>
  <Combobox.Input placeholder="Search framework..." />
  <Combobox.Popover
    renderEmptyState={() => <p className="px-4 py-3 text-center">No match</p>}
  >
    <Combobox.Item id="next">Next.js</Combobox.Item>
    <Combobox.Item id="remix">Remix</Combobox.Item>
    <Combobox.Item id="astro">Astro</Combobox.Item>
  </Combobox.Popover>
</Combobox>

Examples

The free tier covers the input, plain Combobox.Item rows, the empty state, and custom values. Richer previews (smart items, grouped sections) are marked with a Pro badge; the live demo still runs, but the source needs a Pro seat.

Sizes

Three sizes (xs, sm, md) set on the root cascade to the input shell, item height, label, and icon size. sm is the default.

Custom value

Pass allowsCustomValue to accept a typed value that no option matches. Pair it with allowsEmptyCollection so the popover stays open to show the empty state as you type.

Selected: Growth

Token picker

Smart items with a brand icon, a price description, and a trailing holdings amount, grouped under section headers. A grouped combobox filters its own data: keep inputValue controlled, compute the matching groups yourself, and pass them as items on the root (rendered with a function child on Combobox.Popover plus a Collection for each group's items). This bypasses React Aria's built-in filter, which does not support sections.

Pro

Member picker

A searchable assignee list with an Avatar, a name, and a secondary email, grouped into suggested and all members.

Pro
Luca MorettiLM

Accessibility

Combobox inherits React Aria's combobox interaction model. The input owns DOM focus and carries role="combobox" with aria-expanded; arrow keys drive virtual focus (aria-activedescendant) in the role="listbox" popup while you keep typing.

KeyDescription
type textFilters the list to items whose text matches.
↓ ↑Opens the list and moves focus between items.
Home EndJumps to the first / last item.
EnterSelects the focused item and closes the list.
EscCloses the list and reverts the text to the selected value.
TabCommits the selection and moves focus to the next element.

ARIA notes:

  • Give the Combobox an aria-label (or wrap it in a Field with a Label) when there is no visible label; the accessible name lands on the input.
  • The popover closes when the filtered list is empty. Set allowsEmptyCollection on the root to keep it open so renderEmptyState (a no-match hint) can show.
  • With allowsCustomValue, committing text that matches no option keeps that text as the value instead of clearing the field; without it, an unmatched entry reverts on blur.
  • For the full focus, filtering, and selection behavior, see the React Aria ComboBox docs.

Styling

Tailwind override: pass className to merge Tailwind classes on Combobox.Input (the shell), Combobox.Popover, or any sub-part (merged via cn()):

<Combobox.Popover className="w-72" />

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="combobox-input" on the text input, combobox-trigger on the chevron toggle button, combobox-chevron on the icon, combobox-content on the surface, and combobox-listbox on the list. Rows carry combobox-item, groups combobox-group, headings combobox-label. The item internals reuse the dropdown slots: dropdown-item-container / dropdown-item-content / dropdown-item-label / dropdown-item-description / dropdown-item-indicator, plus dropdown-footer.
  • data-size="xs" | "sm" | "md" mirrors the root size; the chevron button carries data-state="open" | "closed".
  • The input trigger reuses the Input shell, so its focus-within, invalid, disabled, and loading borders are identical to a plain Input.
  • React Aria manages data-focused, data-selected, and data-disabled on each item; wrappers style through group-data-[focused]/item and group-data-[selected]/item.

Target a state in CSS:

[data-slot="combobox-item"][data-selected] {
  /* … */
}
  • Select: form-value picker whose trigger is a button showing the value. Use it when the options are a fixed, known set and free text is not needed.
  • Dropdown Menu: the same list surface opened from a button, for commands and actions rather than a value.
  • Command (Pro): a searchable command palette in a modal shell.

API Reference

Combobox.* reuses the Dropdown/Select item surface, so item props match Select.Item. The combobox-specific parts are the root, Combobox.Input, and Combobox.Popover.

Combobox

The root. Wraps React Aria's ComboBox, so its selection, input, and collection props pass through. Provides the size/state context.

Props

PropTypeDefaultDescription
valueKey | null-Controlled selected key. defaultValue for uncontrolled.
onChange(key: Key | null) => void-Fires when the committed selection changes.
inputValuestring-Controlled text value. onInputChange reports edits.
allowsCustomValuebooleanfalseKeep a typed value that matches no option instead of reverting.
allowsEmptyCollectionbooleanfalseKeep the popover open when the filtered list is empty (to show the empty state).
menuTrigger"input" | "focus" | "manual""input"What opens the list: typing, focus, or only the toggle button.
loadingbooleanfalseSwap the chevron for a spinner and lock the field. Falls back to Field.
isDisabledbooleanfalseDisables the field. Falls back to a surrounding Field.
isInvalidbooleanfalseInvalid styling. Falls back to a surrounding Field.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Cascades to the input shell, item height, label, and icon size. Falls back to Field.
variant"default" "compact""default"default is full-width; compact shrinks to fit.

Combobox.Input

The trigger: a text input in the shared Input shell with a trailing chevron toggle. The interior is a slot row, so it hosts leading and trailing content beside the input at the right size, gap, and padding. Pass the selected item's media (a flag, an avatar) as startContent to keep it visible in the field, or a clear button as endContent. Extends the native input props.

Props

PropTypeDefaultDescription
startContentReact.ReactNode-Leading content before the input (search icon, selected media).
endContentReact.ReactNode-Trailing content after the input, before the chevron.
placeholderstring-Placeholder text for the input.
classNamestring-Tailwind classes for the outer input shell.
inputClassNamestring-Tailwind classes for the inner input element.

Combobox.Popover

The floating surface (alias Combobox.Content). Renders the ListBox. Extends React Aria's PopoverProps; defaults to placement="bottom start" and offset={8}.

Props

PropTypeDefaultDescription
renderEmptyState() => ReactNode-Rendered inside the list when it has no items (no filter match).
footerReact.ReactNode-Pinned bar below the list, with a top divider.
placementPlacement"bottom start"Preferred side/alignment relative to the input.
offsetnumber8Distance in pixels from the input.
classNamestring-Tailwind classes merged via cn() (commonly a width).

Combobox.Item

A list row. Mirrors Select.Item. A plain label with an optional leading media, value (alias for id), and size are free; description, trailing, and indicator opt into the smart layout (Pro). textValue, isDisabled, and the React Aria ListBoxItem props pass through. The typed filter matches against textValue (derived from a plain-text label).

Other parts

PartRole
Combobox.Section / GroupGroups related items under a shared label (Pro).
Combobox.LabelThe overline heading at the top of a section (Pro).
Combobox.SeparatorA thin divider between runs of items.
Combobox.FooterA divided bar below the list.
Combobox.MiscPins static content above the list.
Combobox.ItemContainerWraps the media and text block of a row.
Combobox.ItemContentStacks the label and description.
Combobox.ItemLabelThe row's primary text.
Combobox.ItemDescriptionThe secondary line beneath the label.
Combobox.ItemIndicatorThe selection check shown on the selected row.