Add this component

npx zentauri-ui add combobox

Accessibility notes

Keyboard accessible controls with labels, focus-visible rings, and state attributes. Keep visible labels or aria-labels when copying snippets.

Dependency notes

Check Installation for shared peers. This component keeps styling in Tailwind classes and the --zui-* token contract.

Forms

Combobox for searchable selection

Combobox combines a trigger button with a searchable dropdown list. Use it when option lists are too long to scan at a glance, or when users need to type to filter before picking.

Examples

Single-select, multi-select, disabled items, and controlled value patterns with trigger and content variants.





Combobox variants playground

Pick a trigger variant and size plus a content appearance and size to preview the combobox live. Toggle Show output / Show code and the snippet updates to match the selected variant.


Multi-select


Combobox · multi-select, sky appearance

Combobox API

Generated from the package prop types and variant definitions.

Combobox

ComboboxProps

State

PropTypeDefault
defaultValuestring[] | undefinednone
valuestring[] | undefinednone

Behavior

PropTypeDefault
multipleboolean | undefinednone
onChange((value: string[]) => void) | undefinednone

Content

PropTypeDefault
children*ReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone

ComboboxContent

ComboboxContentProps

Variants

PropTypeDefault
appearance
aquabluecrimsoncyandefaultelectricemeraldforestghostglassgradient-bluegradient-green+31
default
size
lgmdsm
md
spacing
defaultlgmdnonesmxl
default
Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxEmpty

ComboboxEmptyProps

Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxItem

ComboboxItemProps

Variants

PropTypeDefault
appearance
aquabluecrimsoncyandefaultelectricemeraldforestghostglassgradient-bluegradient-green+31
default
disabled
true
none

State

PropTypeDefault
value*stringnone

Content

PropTypeDefault
childrenReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxList

ComboboxListProps

Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxSearch

ComboboxSearchProps

Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLInputElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxTrigger

ComboboxTriggerProps

Variants

PropTypeDefault
size
lgmdsm
md
variant
aquabluecrimsoncyandefaultelectricemeraldforestghostglassgradient-bluegradient-green+31
default
Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLButtonElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ComboboxValue

ComboboxValueProps

Behavior

PropTypeDefault
placeholderReactNodenone
Inherited HTML props
PropTypeDefault
childrenReactNodenone
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLSpanElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone
CSS variable overrides

Combobox CSS variables

Override these combobox variables on :root, a theme selector, or a component wrapper to tune the trigger, popup, search field, listbox, items, and empty state.

446 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-combobox-trigger-ring-focus: oklch(44.6% 0.03 256.802);
  --zui-combobox-trigger-default-border: oklch(87.2% 0.01 258.338);
  --zui-combobox-trigger-default-bg: #ffffff;
  --zui-combobox-trigger-default-fg: oklch(13% 0.028 261.692);
  --zui-combobox-trigger-outline-border: oklch(55.1% 0.027 264.364);
  --zui-combobox-trigger-outline-fg: oklch(13% 0.028 261.692);
  --zui-combobox-trigger-ghost-border: transparent;
  --zui-combobox-trigger-ghost-fg: oklch(13% 0.028 261.692);
  --zui-combobox-trigger-sky-border: oklch(44.3% 0.11 240.79);
  --zui-combobox-trigger-sky-fg: oklch(29.3% 0.066 243.157);
  --zui-combobox-trigger-rose-border: oklch(45.5% 0.188 13.697);
  --zui-combobox-trigger-rose-fg: oklch(27.1% 0.105 12.094);
  --zui-combobox-trigger-purple-border: oklch(43.8% 0.218 303.724);
  --zui-combobox-trigger-purple-fg: oklch(29.1% 0.149 302.717);
  --zui-combobox-trigger-pink-border: oklch(45.9% 0.187 3.815);
  --zui-combobox-trigger-pink-fg: oklch(28.4% 0.109 3.907);
  --zui-combobox-trigger-orange-border: oklch(47% 0.157 37.304);
  --zui-combobox-trigger-orange-fg: oklch(26.6% 0.079 36.259);
  --zui-combobox-trigger-yellow-border: oklch(47.6% 0.114 61.907);
  --zui-combobox-trigger-yellow-fg: oklch(28.6% 0.066 53.813);
  --zui-combobox-trigger-teal-border: oklch(43.7% 0.078 188.216);
  --zui-combobox-trigger-teal-fg: oklch(27.7% 0.046 192.524);
  --zui-combobox-trigger-indigo-border: oklch(58.5% 0.233 277.117);
  --zui-combobox-trigger-indigo-fg: oklch(25.7% 0.09 281.288);
  --zui-combobox-trigger-emerald-border: oklch(43.2% 0.095 166.913);
  --zui-combobox-trigger-emerald-fg: oklch(26.2% 0.051 172.552);
  --zui-combobox-trigger-glass-border: #00000026;
  --zui-combobox-trigger-glass-bg: #0000001a;
  --zui-combobox-trigger-glass-fg: oklch(13% 0.028 261.692);
  --zui-combobox-trigger-gradient-blue-from: oklch(37.9% 0.146 265.522);
  --zui-combobox-trigger-gradient-blue-to: oklch(38.1% 0.176 304.987);
  --zui-combobox-trigger-gradient-blue-fg: #ffffff;
  --zui-combobox-trigger-gradient-green-from: oklch(39.3% 0.095 152.535);
  --zui-combobox-trigger-gradient-green-to: oklch(40.5% 0.101 131.063);
  --zui-combobox-trigger-gradient-green-fg: #ffffff;
  --zui-combobox-trigger-gradient-red-from: oklch(39.6% 0.141 25.723);
  --zui-combobox-trigger-gradient-red-to: oklch(40.8% 0.153 2.432);
  --zui-combobox-trigger-gradient-red-fg: #ffffff;
  --zui-combobox-trigger-gradient-yellow-from: oklch(42.1% 0.095 57.708);
  --zui-combobox-trigger-gradient-yellow-to: oklch(40.8% 0.123 38.172);
  --zui-combobox-trigger-gradient-yellow-fg: #ffffff;
  --zui-combobox-trigger-gradient-purple-from: oklch(38.1% 0.176 304.987);
  --zui-combobox-trigger-gradient-purple-to: oklch(40.8% 0.153 2.432);
  --zui-combobox-trigger-gradient-purple-fg: #ffffff;
  --zui-combobox-trigger-gradient-teal-from: oklch(38.6% 0.063 188.416);
  --zui-combobox-trigger-gradient-teal-to: oklch(39.8% 0.07 227.392);
  --zui-combobox-trigger-gradient-teal-fg: #ffffff;
  --zui-combobox-trigger-gradient-indigo-from: oklch(35.9% 0.144 278.697);
  --zui-combobox-trigger-gradient-indigo-to: oklch(38.1% 0.176 304.987);
  --zui-combobox-trigger-gradient-indigo-fg: #ffffff;
  --zui-combobox-trigger-gradient-pink-from: oklch(40.8% 0.153 2.432);
  --zui-combobox-trigger-gradient-pink-to: oklch(41% 0.159 10.272);
  --zui-combobox-trigger-gradient-pink-fg: #ffffff;
  --zui-combobox-trigger-gradient-orange-from: oklch(40.8% 0.123 38.172);
  --zui-combobox-trigger-gradient-orange-to: oklch(39.6% 0.141 25.723);
  --zui-combobox-trigger-gradient-orange-fg: #ffffff;
  --zui-combobox-trigger-blue-border: #2563eb;
  --zui-combobox-trigger-blue-fg: #2563eb;
  --zui-combobox-trigger-blue-bg-hover: #2563eb14;
  --zui-combobox-trigger-cyan-border: #0891b2;
  --zui-combobox-trigger-cyan-fg: #0891b2;
  --zui-combobox-trigger-cyan-bg-hover: #0891b214;
  --zui-combobox-trigger-green-border: #16a34a;
  --zui-combobox-trigger-green-fg: #16a34a;
  --zui-combobox-trigger-green-bg-hover: #16a34a14;
  --zui-combobox-trigger-lime-border: #65a30d;
  --zui-combobox-trigger-lime-fg: #65a30d;
  --zui-combobox-trigger-lime-bg-hover: #65a30d14;
  --zui-combobox-trigger-mint-border: #10b981;
  --zui-combobox-trigger-mint-fg: #10b981;
  --zui-combobox-trigger-mint-bg-hover: #10b98114;
  --zui-combobox-trigger-ocean-border: #0284c7;
  --zui-combobox-trigger-ocean-fg: #0284c7;
  --zui-combobox-trigger-ocean-bg-hover: #0284c714;
  --zui-combobox-trigger-sapphire-border: #1d4ed8;
  --zui-combobox-trigger-sapphire-fg: #1d4ed8;
  --zui-combobox-trigger-sapphire-bg-hover: #1d4ed814;
  --zui-combobox-trigger-lavender-border: #8b5cf6;
  --zui-combobox-trigger-lavender-fg: #8b5cf6;
  --zui-combobox-trigger-lavender-bg-hover: #8b5cf614;
  --zui-combobox-trigger-ruby-border: #be123c;
  --zui-combobox-trigger-ruby-fg: #be123c;
  --zui-combobox-trigger-ruby-bg-hover: #be123c14;
  --zui-combobox-trigger-red-border: #dc2626;
  --zui-combobox-trigger-red-fg: #dc2626;
  --zui-combobox-trigger-red-bg-hover: #dc262614;
  --zui-combobox-trigger-slate-border: #475569;
  --zui-combobox-trigger-slate-fg: #475569;
  --zui-combobox-trigger-slate-bg-hover: #47556914;
  --zui-combobox-trigger-zinc-border: #52525b;
  --zui-combobox-trigger-zinc-fg: #52525b;
  --zui-combobox-trigger-zinc-bg-hover: #52525b14;
  --zui-combobox-trigger-stone-border: #57534e;
  --zui-combobox-trigger-stone-fg: #57534e;
  --zui-combobox-trigger-stone-bg-hover: #57534e14;
  --zui-combobox-trigger-royal-border: #4338ca;
  --zui-combobox-trigger-royal-fg: #4338ca;
  --zui-combobox-trigger-royal-bg-hover: #4338ca14;
  --zui-combobox-trigger-electric-border: #0ea5e9;
  --zui-combobox-trigger-electric-fg: #0ea5e9;
  --zui-combobox-trigger-electric-bg-hover: #0ea5e914;
  --zui-combobox-trigger-forest-border: #166534;
  --zui-combobox-trigger-forest-fg: #166534;
  --zui-combobox-trigger-forest-bg-hover: #16653414;
  --zui-combobox-trigger-sunset-border: #ea580c;
  --zui-combobox-trigger-sunset-fg: #ea580c;
  --zui-combobox-trigger-sunset-bg-hover: #ea580c14;
  --zui-combobox-trigger-magenta-border: #c026d3;
  --zui-combobox-trigger-magenta-fg: #c026d3;
  --zui-combobox-trigger-magenta-bg-hover: #c026d314;
  --zui-combobox-trigger-crimson-border: #b91c1c;
  --zui-combobox-trigger-crimson-fg: #b91c1c;
  --zui-combobox-trigger-crimson-bg-hover: #b91c1c14;
  --zui-combobox-trigger-aqua-border: #0f766e;
  --zui-combobox-trigger-aqua-fg: #0f766e;
  --zui-combobox-trigger-aqua-bg-hover: #0f766e14;
  --zui-combobox-trigger-plum-border: #7e22ce;
  --zui-combobox-trigger-plum-fg: #7e22ce;
  --zui-combobox-trigger-plum-bg-hover: #7e22ce14;
  --zui-combobox-item-ring-focus: oklch(44.6% 0.03 256.802);
  --zui-combobox-item-default-bg: #ffffff;
  --zui-combobox-item-default-fg: oklch(21% 0.034 264.665);
  --zui-combobox-item-default-selected-bg: oklch(92.8% 0.006 264.531);
  --zui-combobox-item-default-selected-fg: oklch(37.3% 0.034 259.733);
  --zui-combobox-item-glass-bg: #0000001a;
  --zui-combobox-item-glass-fg: oklch(37.3% 0.034 259.733);
  --zui-combobox-item-outline-border: oklch(55.1% 0.027 264.364);
  --zui-combobox-item-outline-fg: oklch(21% 0.034 264.665);
  --zui-combobox-item-ghost-border: transparent;
  --zui-combobox-item-ghost-fg: oklch(21% 0.034 264.665);
  --zui-combobox-item-sky-fg: oklch(39.1% 0.09 240.876);
  --zui-combobox-item-sky-bg-hover: color-mix(in oklch, var(--zui-color-sky,oklch(90.1% 0.058 230.902)) 10%, transparent);
  --zui-combobox-item-rose-fg: oklch(41% 0.159 10.272);
  --zui-combobox-item-rose-bg-hover: color-mix(in oklch, var(--zui-color-rose,oklch(89.2% 0.058 10.001)) 10%, transparent);
  --zui-combobox-item-purple-fg: oklch(38.1% 0.176 304.987);
  --zui-combobox-item-purple-bg-hover: color-mix(in oklch, var(--zui-color-purple,oklch(90.2% 0.063 306.703)) 10%, transparent);
  --zui-combobox-item-pink-fg: oklch(40.8% 0.153 2.432);
  --zui-combobox-item-pink-bg-hover: color-mix(in oklch, var(--zui-color-pink,oklch(89.9% 0.061 343.231)) 10%, transparent);
  --zui-combobox-item-orange-fg: oklch(40.8% 0.123 38.172);
  --zui-combobox-item-orange-bg-hover: color-mix(in oklch, var(--zui-color-orange,oklch(90.1% 0.076 70.697)) 10%, transparent);
  --zui-combobox-item-yellow-fg: oklch(42.1% 0.095 57.708);
  --zui-combobox-item-yellow-bg-hover: color-mix(in oklch, var(--zui-color-yellow,oklch(94.5% 0.129 101.54)) 10%, transparent);
  --zui-combobox-item-teal-fg: oklch(38.6% 0.063 188.416);
  --zui-combobox-item-teal-bg-hover: color-mix(in oklch, var(--zui-color-teal,oklch(91% 0.096 180.426)) 10%, transparent);
  --zui-combobox-item-indigo-fg: oklch(35.9% 0.144 278.697);
  --zui-combobox-item-indigo-bg-hover: color-mix(in oklch, var(--zui-color-indigo,oklch(87% 0.065 274.039)) 10%, transparent);
  --zui-combobox-item-emerald-fg: oklch(37.8% 0.077 168.94);
  --zui-combobox-item-emerald-bg-hover: color-mix(in oklch, var(--zui-color-emerald,oklch(90.5% 0.093 164.15)) 10%, transparent);
  --zui-combobox-item-blue-bg-hover: #2563eb18;
  --zui-combobox-item-blue-fg-hover: #2563eb;
  --zui-combobox-item-blue-bg: #2563eb10;
  --zui-combobox-item-blue-fg: #2563eb;
  --zui-combobox-item-cyan-bg-hover: #0891b218;
  --zui-combobox-item-cyan-fg-hover: #0891b2;
  --zui-combobox-item-cyan-bg: #0891b210;
  --zui-combobox-item-cyan-fg: #0891b2;
  --zui-combobox-item-green-bg-hover: #16a34a18;
  --zui-combobox-item-green-fg-hover: #16a34a;
  --zui-combobox-item-green-bg: #16a34a10;
  --zui-combobox-item-green-fg: #16a34a;
  --zui-combobox-item-lavender-bg-hover: #8b5cf618;
  --zui-combobox-item-lavender-fg-hover: #8b5cf6;
  --zui-combobox-item-lavender-bg: #8b5cf610;
  --zui-combobox-item-lavender-fg: #8b5cf6;
  --zui-combobox-item-red-bg-hover: #dc262618;
  --zui-combobox-item-red-fg-hover: #dc2626;
  --zui-combobox-item-red-bg: #dc262610;
  --zui-combobox-item-red-fg: #dc2626;
  --zui-combobox-content-border: #0000001a;
  --zui-combobox-content-bg: #ffffff;
  --zui-combobox-content-shadow: 0 4px 12px rgba(15,23,42,0.12);
  --zui-combobox-content-default-bg: #ffffff;
  --zui-combobox-content-default-shadow: 0 4px 12px rgba(15,23,42,0.12);
  --zui-combobox-content-glass-bg: #0000001a;
  --zui-combobox-content-outline-border: oklch(55.1% 0.027 264.364);
  --zui-combobox-content-ghost-border: transparent;
  --zui-combobox-content-sky-border: oklch(39.1% 0.09 240.876);
  --zui-combobox-content-rose-border: oklch(41% 0.159 10.272);
  --zui-combobox-content-purple-border: oklch(38.1% 0.176 304.987);
  --zui-combobox-content-pink-border: oklch(40.8% 0.153 2.432);
  --zui-combobox-content-orange-border: oklch(40.8% 0.123 38.172);
  --zui-combobox-content-yellow-border: oklch(42.1% 0.095 57.708);
  --zui-combobox-content-teal-border: oklch(38.6% 0.063 188.416);
  --zui-combobox-content-indigo-border: oklch(35.9% 0.144 278.697);
  --zui-combobox-content-emerald-border: oklch(37.8% 0.077 168.94);
  --zui-combobox-content-blue-border: #2563eb;
  --zui-combobox-content-blue-bg: #2563eb14;
  --zui-combobox-content-red-border: #dc2626;
  --zui-combobox-content-red-bg: #dc262614;
  --zui-combobox-search-border: oklch(87.2% 0.01 258.338);
  --zui-combobox-search-placeholder: oklch(55.1% 0.027 264.364);
  --zui-combobox-search-fg: oklch(13% 0.028 261.692);
  --zui-combobox-search-icon: currentColor;
  --zui-combobox-list-default-border: oklch(87.2% 0.01 258.338);
  --zui-combobox-list-default-ring: oklch(44.6% 0.03 256.802);
  --zui-combobox-list-glass-border: #0000001a;
  --zui-combobox-list-glass-ring: oklch(44.6% 0.03 256.802);
  --zui-combobox-list-outline-border: oklch(55.1% 0.027 264.364);
  --zui-combobox-list-outline-ring: oklch(55.1% 0.027 264.364);
  --zui-combobox-list-ghost-ring: oklch(44.6% 0.03 256.802);
  --zui-combobox-list-sky-border: oklch(39.1% 0.09 240.876);
  --zui-combobox-list-sky-ring: oklch(39.1% 0.09 240.876);
  --zui-combobox-list-rose-border: oklch(41% 0.159 10.272);
  --zui-combobox-list-rose-ring: oklch(41% 0.159 10.272);
  --zui-combobox-list-purple-border: oklch(38.1% 0.176 304.987);
  --zui-combobox-list-purple-ring: oklch(38.1% 0.176 304.987);
  --zui-combobox-list-pink-border: oklch(40.8% 0.153 2.432);
  --zui-combobox-list-pink-ring: oklch(40.8% 0.153 2.432);
  --zui-combobox-list-orange-border: oklch(40.8% 0.123 38.172);
  --zui-combobox-list-orange-ring: oklch(40.8% 0.123 38.172);
  --zui-combobox-list-yellow-border: oklch(42.1% 0.095 57.708);
  --zui-combobox-list-yellow-ring: oklch(42.1% 0.095 57.708);
  --zui-combobox-list-teal-border: oklch(38.6% 0.063 188.416);
  --zui-combobox-list-teal-ring: oklch(38.6% 0.063 188.416);
  --zui-combobox-list-indigo-border: oklch(35.9% 0.144 278.697);
  --zui-combobox-list-indigo-ring: oklch(35.9% 0.144 278.697);
  --zui-combobox-list-emerald-border: oklch(37.8% 0.077 168.94);
  --zui-combobox-list-emerald-ring: oklch(37.8% 0.077 168.94);
  --zui-combobox-list-blue-border: #2563eb;
  --zui-combobox-list-blue-ring: #2563eb;
  --zui-combobox-list-red-border: #dc2626;
  --zui-combobox-list-red-ring: #dc2626;
  --zui-combobox-empty-fg: oklch(55.1% 0.027 264.364);
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-combobox-trigger-ring-focus-dark: oklch(70.7% 0.022 261.325);
  --zui-combobox-trigger-default-border-dark: oklch(87.2% 0.01 258.338);
  /* ...same variables with -dark at the end */
}

What it does

A compound component split into trigger, content panel, search input, list, items, and an empty state.

The search input filters visible items client-side matching on value and label text.

Composition and API

Wrap with Combobox for context. Place ComboboxTrigger (with ComboboxValue) and ComboboxContent (with ComboboxSearch, ComboboxList, and ComboboxItem) as children.

All sub-components accept className and data-slot for easy slot-level targeting.

Common use cases

Comboboxes are ideal for situations where users need to select from a large list of options, such as country selectors, timezone pickers, user assignment dropdowns in project management tools, or multi-select tag and label inputs.

Accessibility

The search input carries role combobox and aria-controls pointing to the listbox. Active item is tracked via aria-activedescendant. Disabled items are marked aria-disabled and ignored by keyboard and pointer.

Test with keyboard-only flows and screen readers when integrating.

Next.js integration notes

Import from the ui/combobox subpath entry. Mark the parent subtree as a Client Component when using onChange or controlled value.

Set NEXT_PUBLIC_SITE_URL so canonical and Open Graph URLs resolve correctly on deploy.

FAQ

How is Combobox different from Select?

Combobox adds a search input inside the dropdown panel so users can type to filter options in real time. Select is a plain listbox with no filtering.

Does Combobox support multiple selection?

Yes. Set multiple on the root Combobox and the panel stays open after each pick. Deselect by clicking a selected item again.

Is Combobox accessible by default?

The search input has role combobox, the list has role listbox, and items have role option. Keyboard navigation with ArrowDown/Up, Enter, and Escape is built in.