ComboBox

PreviousNext

A combo box combines a text input with a listbox, allowing users to filter a list of options to items matching a query.

"use client"

import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"

const frameworks = [
  { id: "next.js", name: "Next.js" },
  { id: "sveltekit", name: "SvelteKit" },
  { id: "nuxt.js", name: "Nuxt.js" },
  { id: "remix", name: "Remix" },
  { id: "astro", name: "Astro" },
  { id: "vue", name: "Vue" },
  { id: "angular", name: "Angular" },
]

export function ComboboxDemo() {
  return (
    <ComboBox
      label="Favorite Framework"
      placeholder="Search framework..."
      className="w-full max-w-xs"
    >
      {frameworks.map((framework) => (
        <ComboBoxItem
          key={framework.id}
          id={framework.id}
          textValue={framework.name}
        >
          {framework.name}
        </ComboBoxItem>
      ))}
    </ComboBox>
  )
}

Installation

pnpm dlx shadcn@latest add combobox

Usage

import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"
<ComboBox
  label="Favorite Framework"
  placeholder="Search framework..."
  className="w-full max-w-xs"
>
  <ComboBoxItem id="next.js" textValue="Next.js">
    Next.js
  </ComboBoxItem>
  <ComboBoxItem id="sveltekit" textValue="SvelteKit">
    SvelteKit
  </ComboBoxItem>
  <ComboBoxItem id="nuxt.js" textValue="Nuxt.js">
    Nuxt.js
  </ComboBoxItem>
  <ComboBoxItem id="remix" textValue="Remix">
    Remix
  </ComboBoxItem>
  <ComboBoxItem id="astro" textValue="Astro">
    Astro
  </ComboBoxItem>
</ComboBox>

Examples

With Sections

import {
  ComboBox,
  ComboBoxItem,
  ComboBoxSection,
} from "@/components/ui/combobox"

export function ComboboxSections() {
  return (
    <ComboBox
      label="Select Language"
      placeholder="Search languages..."
      className="w-full max-w-xs"
    >
      <ComboBoxSection title="Popular">
        <ComboBoxItem id="js" textValue="JavaScript">
          JavaScript
        </ComboBoxItem>
        <ComboBoxItem id="ts" textValue="TypeScript">
          TypeScript
        </ComboBoxItem>
        <ComboBoxItem id="python" textValue="Python">
          Python
        </ComboBoxItem>
      </ComboBoxSection>
      <ComboBoxSection title="Web">
        <ComboBoxItem id="html" textValue="HTML">
          HTML
        </ComboBoxItem>
        <ComboBoxItem id="css" textValue="CSS">
          CSS
        </ComboBoxItem>
        <ComboBoxItem id="php" textValue="PHP">
          PHP
        </ComboBoxItem>
      </ComboBoxSection>
      <ComboBoxSection title="Systems">
        <ComboBoxItem id="rust" textValue="Rust">
          Rust
        </ComboBoxItem>
        <ComboBoxItem id="go" textValue="Go">
          Go
        </ComboBoxItem>
        <ComboBoxItem id="c" textValue="C">
          C
        </ComboBoxItem>
        <ComboBoxItem id="cpp" textValue="C++">
          C++
        </ComboBoxItem>
      </ComboBoxSection>
    </ComboBox>
  )
}
<ComboBox
  label="Select Language"
  placeholder="Search languages..."
  className="w-full max-w-xs"
>
  <ComboBoxSection title="Popular">
    <ComboBoxItem id="js" textValue="JavaScript">
      JavaScript
    </ComboBoxItem>
    <ComboBoxItem id="ts" textValue="TypeScript">
      TypeScript
    </ComboBoxItem>
  </ComboBoxSection>
  <ComboBoxSection title="Web">
    <ComboBoxItem id="html" textValue="HTML">
      HTML
    </ComboBoxItem>
    <ComboBoxItem id="css" textValue="CSS">
      CSS
    </ComboBoxItem>
  </ComboBoxSection>
</ComboBox>

Controlled

"use client"

import { useState } from "react"

import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"

const countries = [
  { id: "us", name: "United States" },
  { id: "uk", name: "United Kingdom" },
  { id: "ca", name: "Canada" },
  { id: "au", name: "Australia" },
  { id: "de", name: "Germany" },
  { id: "fr", name: "France" },
  { id: "jp", name: "Japan" },
  { id: "in", name: "India" },
]

export function ComboboxControlled() {
  const [selectedKey, setSelectedKey] = useState<string | null>(null)

  return (
    <div className="space-y-4">
      <ComboBox
        label="Select Country"
        placeholder="Search countries..."
        className="w-full max-w-xs"
        selectedKey={selectedKey}
        onSelectionChange={(key) => setSelectedKey(key as string)}
      >
        {countries.map((country) => (
          <ComboBoxItem
            key={country.id}
            id={country.id}
            textValue={country.name}
          >
            {country.name}
          </ComboBoxItem>
        ))}
      </ComboBox>
      {selectedKey && (
        <p className="text-muted-foreground text-sm">
          Selected: {countries.find((c) => c.id === selectedKey)?.name}
        </p>
      )}
    </div>
  )
}
const [selectedKey, setSelectedKey] = useState<string | null>(null)
 
<ComboBox
  label="Select Country"
  placeholder="Search countries..."
  selectedKey={selectedKey}
  onSelectionChange={(key) => setSelectedKey(key as string)}
>
  <ComboBoxItem id="us" textValue="United States">
    United States
  </ComboBoxItem>
  <ComboBoxItem id="uk" textValue="United Kingdom">
    United Kingdom
  </ComboBoxItem>
  <ComboBoxItem id="ca" textValue="Canada">
    Canada
  </ComboBoxItem>
</ComboBox>

With Description

Choose your preferred code editor for development.
import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"

const editors = [
  { id: "vscode", name: "Visual Studio Code" },
  { id: "sublime", name: "Sublime Text" },
  { id: "atom", name: "Atom" },
  { id: "vim", name: "Vim" },
  { id: "neovim", name: "Neovim" },
  { id: "emacs", name: "Emacs" },
]

export function ComboboxDescription() {
  return (
    <ComboBox
      label="Code Editor"
      description="Choose your preferred code editor for development."
      placeholder="Search editors..."
      className="w-full max-w-xs"
    >
      {editors.map((editor) => (
        <ComboBoxItem key={editor.id} id={editor.id} textValue={editor.name}>
          {editor.name}
        </ComboBoxItem>
      ))}
    </ComboBox>
  )
}
<ComboBox
  label="Code Editor"
  description="Choose your preferred code editor for development."
  placeholder="Search editors..."
>
  <ComboBoxItem id="vscode" textValue="Visual Studio Code">
    Visual Studio Code
  </ComboBoxItem>
  <ComboBoxItem id="sublime" textValue="Sublime Text">
    Sublime Text
  </ComboBoxItem>
  <ComboBoxItem id="vim" textValue="Vim">
    Vim
  </ComboBoxItem>
</ComboBox>

Disabled

import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"

const options = [
  { id: "option1", name: "Option 1" },
  { id: "option2", name: "Option 2" },
  { id: "option3", name: "Option 3" },
]

export function ComboboxDisabled() {
  return (
    <ComboBox
      label="Disabled ComboBox"
      placeholder="Cannot interact..."
      className="w-full max-w-xs"
      isDisabled
    >
      {options.map((option) => (
        <ComboBoxItem key={option.id} id={option.id} textValue={option.name}>
          {option.name}
        </ComboBoxItem>
      ))}
    </ComboBox>
  )
}
<ComboBox
  label="Disabled ComboBox"
  placeholder="Cannot interact..."
  isDisabled
>
  <ComboBoxItem id="option1">Option 1</ComboBoxItem>
  <ComboBoxItem id="option2">Option 2</ComboBoxItem>
</ComboBox>

Validation

"use client"

import { ComboBox, ComboBoxItem } from "@/components/ui/combobox"

const priorities = [
  { id: "low", name: "Low" },
  { id: "medium", name: "Medium" },
  { id: "high", name: "High" },
  { id: "urgent", name: "Urgent" },
]

export function ComboboxValidation() {
  return (
    <ComboBox
      label="Priority"
      placeholder="Select priority..."
      className="w-full max-w-xs"
      isRequired
      errorMessage="Please select a priority level."
    >
      {priorities.map((priority) => (
        <ComboBoxItem
          key={priority.id}
          id={priority.id}
          textValue={priority.name}
        >
          {priority.name}
        </ComboBoxItem>
      ))}
    </ComboBox>
  )
}
<ComboBox
  label="Priority"
  placeholder="Select priority..."
  isRequired
  errorMessage="Please select a priority level."
>
  <ComboBoxItem id="low">Low</ComboBoxItem>
  <ComboBoxItem id="medium">Medium</ComboBoxItem>
  <ComboBoxItem id="high">High</ComboBoxItem>
</ComboBox>

API Reference

ComboBox

The ComboBox component combines a text input with a listbox, providing autocomplete and filtering functionality.

PropTypeDefaultDescription
labelstring-Label text for the combobox
placeholderstring-Placeholder text for the input
descriptionstring-Help text displayed below the combobox
errorMessagestring | ((validation: ValidationResult) => string)-Error message for validation
isDisabledbooleanfalseWhether the combobox is disabled
isRequiredbooleanfalseWhether the combobox is required
size"default" | "sm""default"Size variant of the combobox
selectedKeystring | null-Controlled selected key
defaultSelectedKeystring | null-Default selected key (uncontrolled)
onSelectionChange(key: string | null) => void-Callback when selection changes
itemsIterable<T>-Collection of items for dynamic rendering

ComboBoxItem

The ComboBoxItem component represents an option in the combobox list.

PropTypeDefaultDescription
idstring-Unique identifier for the item
textValuestring-Text value used for filtering/searching
isDisabledbooleanfalseWhether the item is disabled

ComboBoxSection

The ComboBoxSection component groups related items together.

PropTypeDefaultDescription
titlestring-Section header text
itemsIterable<T>-Collection of items in the section

Features

  • Autocomplete: Filter options as you type
  • Keyboard Navigation: Full keyboard support with arrow keys and Enter
  • Accessibility: Built on react-aria with ARIA best practices
  • Custom Values: Support for user-entered custom values (when enabled)
  • Sections: Organize options into labeled groups
  • Validation: Built-in support for required fields and error messages
  • Responsive: Works on mobile and desktop devices