Skip to content

Now in the official shadcn registry directory.

Start free

Combobox

A searchable single-select composed from Popover and Command. Pass options, get fuzzy search and keyboard navigation for free.

form
A free styled version is available

Installation

Run the following command

npx shadcn@latest add @ai2/combobox

Dependencies, the @ai2/tokens theme and the component file are installed together. The @ai2/button, @ai2/command and @ai2/popover components install alongside, since the combobox is composed from them.

Usage

TS
import { Combobox } from "@/components/ui/combobox"

const frameworks = [
  { value: "next", label: "Next.js" },
  { value: "astro", label: "Astro" },
  { value: "remix", label: "Remix" },
]

<Combobox options={frameworks} placeholder="Select a framework…" />

The combobox works uncontrolled out of the box; pass value and onValueChange to control it. Selecting the active option again clears the value.

Examples

Default value

Disabled

Disable the whole combobox with disabled, or a single option with disabled: true in its options entry, here the Enterprise plan.

Variants

The trigger follows the shared input contract: variant, size and tone match the ai2 Input and Select.

Sizes

Tones

tone colors the trigger border and focus ring for validation states, matching the ai2 Input and Select.

Custom text

Props

Combobox is a closed composition. It exposes exactly these props (plus the ComboboxOption type).

PropTypeDefaultDescription
optionsComboboxOption[]-The selectable options as { value, label, disabled? } objects. Required.
valuestring-Controlled selected value. Pair with onValueChange.
defaultValuestring""Initial value for uncontrolled usage.
onValueChange(value: string) => void-Called with the new value on selection, or with an empty string when the active option is selected again (clearing it).
placeholderstring"Select an option…"Trigger text while nothing is selected.
searchPlaceholderstring"Search…"Placeholder of the search input.
emptyTextstring"No results found."Message shown when the search matches no option.
disabledboolean-Disables the trigger button.
variant"outline" | "soft" | "ghost""outline"Visual style of the trigger: bordered, filled or transparent.
size"sm" | "md" | "lg""md"Height of the trigger button.
tone"neutral" | "success" | "danger""neutral"Validation look: colors the trigger border and focus ring.
classNamestring-Extra classes for the trigger button (default width is w-56).

ai2 Combobox: a searchable select for React, built from Popover and Command

The ai2 Combobox is a shadcn-compatible combobox component for React, a searchable single-select composed from the ai2 Popover, Command and Button and styled with Tailwind CSS v4. You pass an array of value and label pairs; it handles the open state, text filtering, keyboard navigation and the selected check mark, so long option lists like countries, regions, models or team members stay usable.

Because it ships through the shadcn registry format, you install it with one CLI command, an MCP agent, or a copy-paste, and the source lands in your own project along with the button, command and popover it is built from. You own every file; there is no runtime dependency on ai2 itself. The live example above is the exact component you get.

What is the ai2 Combobox?

Unlike most registry items, it is a closed composition: a single Combobox component that wires an ai2 Button trigger into a Popover holding a cmdk-powered Command list. This is the same pattern the shadcn/ui docs describe for building a combobox, packaged as one component with a typed options prop.

It works uncontrolled with defaultValue or controlled with value and onValueChange. Selecting the active option again clears the value, per option disabling is a flag on the options entry, and the popover panel matches the trigger width through the radix trigger-width variable. The trigger follows the shared ai2 input contract: a variant of outline, soft or ghost, a size of sm, md or lg, and a tone of neutral, success or danger that colors the border and focus ring for validation states.

Why use it

  • Search built in: The cmdk-powered list filters as the user types, so a 200-entry option list stays as fast to use as a five-entry one.
  • One prop, whole behavior: Pass options as { value, label, disabled? } objects and the component handles open state, filtering, selection and the check indicator.
  • Accessible trigger semantics: The trigger is a real button with role="combobox" and aria-expanded, and the list inherits cmdk keyboard navigation: arrows move, Enter selects, Escape closes.
  • Controlled or uncontrolled: Use defaultValue for simple forms, or drive value and onValueChange from React state when other UI depends on the selection.
  • Composed from parts you own: Installing @ai2/combobox brings the ai2 button, command and popover with it. If you outgrow the closed API, open the source and extend the composition directly.

Features

  • shadcn registry install: One command adds the combobox plus its button, command and popover dependencies and the @ai2/tokens theme.
  • 3 variants, 3 sizes and 3 tones: The trigger offers outline, soft and ghost variants, sm, md and lg sizes, and neutral, success and danger tones, aligned with the ai2 Input and Select contract.
  • Clear-on-reselect: Selecting the active option again resets the value to an empty string, giving users a way to clear without a separate button.
  • Per-option disabling: Set disabled: true on any options entry to show it muted and unselectable, for example a plan the workspace cannot choose.
  • Trigger-width panel: The popover content uses the radix trigger-width variable, so the list always lines up with the button regardless of the className you set.
  • Customizable copy: placeholder, searchPlaceholder and emptyText are plain string props, so localization needs no source edits.
  • TypeScript source: ComboboxProps and ComboboxOption are exported, typed end to end, so autocomplete covers the full API.

Production tips

  • Use it when lists get long: Under roughly ten options, a plain ai2 Select is simpler. The combobox earns its search box on long or unfamiliar lists like countries or users.
  • Keep labels searchable: Filtering matches what users type against the option text. Front-load the meaningful part of each label instead of prefixing every entry with the same word.
  • Give it an accessible name: The trigger only announces the selected label. Associate a visible label with aria-labelledby, or set aria-label when the design has no room for one.
  • Handle the cleared state: Reselecting the active option calls onValueChange with an empty string. Make sure your form logic treats that as unset rather than crashing on it.
  • Size the trigger deliberately: The default width is w-56 and long labels truncate. Pass a wider className when option labels run long, and the panel follows automatically.

Works with the rest of ai2

The combobox is literally built from ai2 Popover, ai2 Command and ai2 Button, so reading those pages explains its internals. In forms, pair it with an ai2 Field for label, description and error wiring.

When the option list is short and search adds nothing, use the ai2 Select instead. Both share the same popover surface and token source, so swapping one for the other later is a local change.

FAQs

Get new components in your inbox

Component drops, new themes and release notes. No spam, and you can unsubscribe from any email.

© 2026 ai2 design system · MIT licensed · Built with its own components