Combobox

A filterable input for selecting one or more options.

Type to narrow the list, then choose an option. Selection is single by default; set multiple to work with chips.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]export function Example() {  return (    <Combobox>      <ComboboxInput placeholder="Select a framework" />      <ComboboxContent>        <ComboboxEmpty>No frameworks found.</ComboboxEmpty>        <ComboboxList>          {frameworks.map((framework) => (            <ComboboxItem key={framework} value={framework}>              {framework}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add combobox

Usage

import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"
<Combobox>  <ComboboxInput placeholder="Pick a workspace" />  <ComboboxContent>    <ComboboxEmpty>No workspaces found.</ComboboxEmpty>    <ComboboxList>      <ComboboxItem value="design">Design</ComboboxItem>      <ComboboxItem value="docs">Docs</ComboboxItem>    </ComboboxList>  </ComboboxContent></Combobox>

Composition

Combobox
├── ComboboxInput
└── ComboboxContent
    ├── ComboboxEmpty
    └── ComboboxList
        ├── ComboboxItem
        └── ComboboxItem

With chips:

Combobox
├── ComboboxChips
│   ├── ComboboxChip
│   └── ComboboxChipsInput
└── ComboboxContent
    ├── ComboboxEmpty
    └── ComboboxList

With trigger (popup):

Combobox
├── ComboboxTrigger
│   └── ComboboxValue
└── ComboboxContent
    ├── ComboboxInput
    ├── ComboboxEmpty
    └── ComboboxList

Basic

A single field with a flat list that filters as you type.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]export function Example() {  return (    <Combobox>      <ComboboxInput placeholder="Select a framework" />      <ComboboxContent>        <ComboboxEmpty>No frameworks found.</ComboboxEmpty>        <ComboboxList>          {frameworks.map((framework) => (            <ComboboxItem key={framework} value={framework}>              {framework}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

With icon

Pass a leading icon with startAddon. Add startAddonAlways to keep it visible when the list is closed.

tsx
import type { SVGProps } from "react"import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const countries = ["Sweden", "Norway", "Denmark", "Finland", "Iceland"]function GlobeIcon(props: SVGProps<SVGSVGElement>) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      {...props}    >      <circle cx="12" cy="12" r="10" />      <path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />      <path d="M2 12h20" />    </svg>  )}export function Example() {  return (    <Combobox>      <ComboboxInput        placeholder="Select country"        startAddonAlways        startAddon={          <GlobeIcon className="size-3.5 text-muted-foreground" />        }      />      <ComboboxContent>        <ComboboxEmpty>No countries found.</ComboboxEmpty>        <ComboboxList>          {countries.map((country) => (            <ComboboxItem key={country} value={country}>              {country}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Multiple

Set multiple to represent each selected value as a chip.

Next.js
tsx
import * as React from "react"import {  Combobox,  ComboboxChip,  ComboboxChips,  ComboboxChipsInput,  ComboboxContent,  ComboboxEmpty,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]export function Example() {  const [value, setValue] = React.useState<string[]>(["Next.js"])  return (    <Combobox      multiple      value={value}      onValueChange={(next) => setValue(next as string[])}    >      <ComboboxChips>        {value.map((item) => (          <ComboboxChip key={item} value={item}>            {item}          </ComboboxChip>        ))}        <ComboboxChipsInput />      </ComboboxChips>      <ComboboxContent>        <ComboboxEmpty>No frameworks found.</ComboboxEmpty>        <ComboboxList>          {frameworks.map((framework) => (            <ComboboxItem key={framework} value={framework}>              {framework}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Clear button

Pass showClear to add a clear control to the input.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]export function Example() {  return (    <Combobox defaultValue="Next.js" showClear>      <ComboboxInput placeholder="Select a framework" />      <ComboboxContent>        <ComboboxEmpty>No frameworks found.</ComboboxEmpty>        <ComboboxList>          {frameworks.map((framework) => (            <ComboboxItem key={framework} value={framework}>              {framework}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Groups

Organize longer lists with ComboboxGroup, ComboboxLabel, and ComboboxSeparator.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxGroup,  ComboboxInput,  ComboboxItem,  ComboboxLabel,  ComboboxList,  ComboboxSeparator,} from "@/components/ui/combobox"export function Example() {  return (    <Combobox>      <ComboboxInput placeholder="Search docs" />      <ComboboxContent>        <ComboboxEmpty>No pages found.</ComboboxEmpty>        <ComboboxList>          <ComboboxGroup>            <ComboboxLabel>Components</ComboboxLabel>            <ComboboxItem value="button">Button</ComboboxItem>            <ComboboxItem value="card">Card</ComboboxItem>            <ComboboxItem value="combobox">Combobox</ComboboxItem>          </ComboboxGroup>          <ComboboxSeparator />          <ComboboxGroup>            <ComboboxLabel>Guides</ComboboxLabel>            <ComboboxItem value="installation">Installation</ComboboxItem>            <ComboboxItem value="theming">Theming</ComboboxItem>            <ComboboxItem value="cli">CLI</ComboboxItem>          </ComboboxGroup>        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Custom items

Pass rich content to ComboboxItem, then set label for filtering and the input value.

tsx
import * as React from "react"import {  Avatar,  AvatarFallback,  AvatarImage,} from "@/components/ui/avatar"import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"const members = [  {    value: "mina",    name: "Mina Cho",    email: "mina@arctis.dev",    fallback: "MC",    src: "/assets/brand/demos/avatars/avatar-1.png",  },  {    value: "jonas",    name: "Jonas Berg",    email: "jonas@arctis.dev",    fallback: "JB",    src: "/assets/brand/demos/avatars/avatar-2.png",  },  {    value: "elsa",    name: "Elsa Lind",    email: "elsa@arctis.dev",    fallback: "EL",    src: "/assets/brand/demos/avatars/avatar-3.png",  },  {    value: "noah",    name: "Noah Park",    email: "noah@arctis.dev",    fallback: "NP",    src: "/assets/brand/demos/avatars/avatar-4.png",  },]export function Example() {  const [value, setValue] = React.useState("")  const selected = members.find((member) => member.value === value)  return (    <Combobox value={value} onValueChange={(next) => setValue(next as string)}>      <ComboboxInput        placeholder="Assign to…"        startAddon={          selected ? (            <Avatar size="xs" className="ring-0">              <AvatarImage src={selected.src} alt={selected.name} />              <AvatarFallback>{selected.fallback}</AvatarFallback>            </Avatar>          ) : null        }      />      <ComboboxContent>        <ComboboxEmpty>No members found.</ComboboxEmpty>        <ComboboxList>          {members.map((member) => (            <ComboboxItem              key={member.value}              value={member.value}              label={member.name}            >              <span className="flex items-center gap-2">                <Avatar size="xs" className="ring-0">                  <AvatarImage src={member.src} alt={member.name} />                  <AvatarFallback>{member.fallback}</AvatarFallback>                </Avatar>                <span className="flex min-w-0 flex-col">                  <span className="truncate">{member.name}</span>                  <span className="truncate text-xs text-muted-foreground">                    {member.email}                  </span>                </span>              </span>            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Invalid

Set invalid on the root to apply the destructive border treatment.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"export function Example() {  return (    <Combobox invalid defaultValue="npm" showClear>      <ComboboxInput placeholder="Pick a package manager" />      <ComboboxContent>        <ComboboxEmpty>No matches.</ComboboxEmpty>        <ComboboxList>          <ComboboxItem value="pnpm">pnpm</ComboboxItem>          <ComboboxItem value="npm">npm</ComboboxItem>          <ComboboxItem value="yarn">yarn</ComboboxItem>          <ComboboxItem value="bun">bun</ComboboxItem>        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Disabled

Set disabled to make the field and its list unavailable.

tsx
import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,} from "@/components/ui/combobox"export function Example() {  return (    <Combobox disabled defaultValue="Next.js">      <ComboboxInput placeholder="Select a framework" />      <ComboboxContent>        <ComboboxEmpty>No frameworks found.</ComboboxEmpty>        <ComboboxList>          <ComboboxItem value="Next.js">Next.js</ComboboxItem>          <ComboboxItem value="Remix">Remix</ComboboxItem>        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

Use ComboboxTrigger to open the list from a button, with the search field inside the panel.

tsx
import * as React from "react"import {  Combobox,  ComboboxContent,  ComboboxEmpty,  ComboboxInput,  ComboboxItem,  ComboboxList,  ComboboxTrigger,  ComboboxValue,} from "@/components/ui/combobox"const countries = ["Sweden", "Norway", "Denmark", "Finland", "Iceland"]function SearchIcon(props: React.SVGProps<SVGSVGElement>) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      {...props}    >      <circle cx="11" cy="11" r="8" />      <path d="m21 21-4.3-4.3" />    </svg>  )}export function Example() {  const [value, setValue] = React.useState("")  return (    <Combobox value={value} onValueChange={(next) => setValue(next as string)}>      <ComboboxTrigger>        <ComboboxValue placeholder="Select country" />      </ComboboxTrigger>      <ComboboxContent className="p-0">        <div className="border-b border-border px-1 py-1">          <ComboboxInput            placeholder="Search country"            showIcon={false}            filterOnly            startAddon={              <SearchIcon className="size-3.5 text-muted-foreground" />            }            className="h-8 border-0 pr-2 text-[13px]"          />        </div>        <ComboboxEmpty>No countries found.</ComboboxEmpty>        <ComboboxList>          {countries.map((country) => (            <ComboboxItem key={country} value={country}>              {country}            </ComboboxItem>          ))}        </ComboboxList>      </ComboboxContent>    </Combobox>  )}

API Reference

Combobox

PropTypeDefault
valuestring | string[]
defaultValuestring | string[]
onValueChange(value: string | string[]) => void
multiplebooleanfalse
disabledbooleanfalse
invalidbooleanfalse
showClearbooleanfalse
autoHighlightbooleanfalse
openboolean
defaultOpenbooleanfalse
onOpenChange(open: boolean) => void
classNamestring
<Combobox>  <ComboboxInput placeholder="Search..." />  <ComboboxContent>    <ComboboxEmpty>No results.</ComboboxEmpty>    <ComboboxItem value="apple">Apple</ComboboxItem>  </ComboboxContent></Combobox>

ComboboxInput

PropTypeDefault
placeholderstring"Select…"
startAddonReactNode
startAddonAlwaysbooleanfalse
showIconbooleantrue
filterOnlybooleanfalse
classNamestring
<ComboboxInput placeholder="Search..." />

ComboboxTrigger

PropTypeDefault
classNamestring
<ComboboxTrigger />

ComboboxValue

PropTypeDefault
placeholderstring"Select…"
childrenReactNode
classNamestring
<ComboboxValue placeholder="Select..." />

ComboboxContent

PropTypeDefault
classNamestring
<ComboboxContent>  <ComboboxItem value="apple">Apple</ComboboxItem></ComboboxContent>

ComboboxEmpty

PropTypeDefault
childrenReactNode"No items found."
classNamestring
<ComboboxEmpty>No results.</ComboboxEmpty>

ComboboxItem

PropTypeDefault
valuestring
labelstring
disabledbooleanfalse
classNamestring
<ComboboxItem value="apple">Apple</ComboboxItem>

ComboboxChips

PropTypeDefault
classNamestring
<ComboboxChips>  <ComboboxChip value="apple">Apple</ComboboxChip>  <ComboboxChipsInput /></ComboboxChips>

ComboboxChip

PropTypeDefault
valuestring
childrenReactNode
classNamestring
<ComboboxChip value="apple">Apple</ComboboxChip>

ComboboxChipsInput

PropTypeDefault
placeholderstring
classNamestring
<ComboboxChipsInput />

ComboboxGroup

PropTypeDefault
classNamestring
<ComboboxGroup>  <ComboboxLabel>Fruit</ComboboxLabel>  <ComboboxItem value="apple">Apple</ComboboxItem></ComboboxGroup>

ComboboxLabel

PropTypeDefault
classNamestring
<ComboboxLabel>Fruit</ComboboxLabel>

ComboboxSeparator

PropTypeDefault
classNamestring
<ComboboxSeparator />