Combobox
Autocomplete input and command palette with a list of suggestions.
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
const frameworks = ['Next.js', 'SvelteKit', 'Nuxt', 'Remix', 'Astro'];
export default function ComboboxDemo() {
return (
<Combobox items={frameworks}>
<ComboboxInput placeholder="Search framework…" />
<ComboboxContent>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Install
npx shadcn@latest add @madeui/combobox
Usage
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
Composition
Simple
A single-line input and a flat list.
<Combobox items={items}>
<ComboboxInput />
<ComboboxContent>
<ComboboxEmpty />
<ComboboxList>
{(item) => <ComboboxItem value={item} />}
</ComboboxList>
</ComboboxContent>
</Combobox>
With chips
Multi-select with multiple, chips, and a chips input. ComboboxChips also
serves as the popup anchor — pass a ref to ComboboxContent’s anchor.
<Combobox items={items} multiple value={value} onValueChange={setValue}>
<ComboboxChips ref={anchorRef}>
<ComboboxValue>
{(values) => values.map((value) => <ComboboxChip key={value}>{value}</ComboboxChip>)}
</ComboboxValue>
<ComboboxChipsInput />
</ComboboxChips>
<ComboboxContent anchor={anchorRef}>
<ComboboxEmpty />
<ComboboxList>
{(item) => <ComboboxItem value={item} />}
</ComboboxList>
</ComboboxContent>
</Combobox>
Multiple
Use multiple with ComboboxChips for multi-select. Selected values render
as removable chips inline with the input.
'use client';
import * as React from 'react';
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxValue,
} from '@/components/ui/combobox';
const frameworks = ['Next.js', 'SvelteKit', 'Nuxt', 'Remix', 'Astro'];
export default function ComboboxMultiple() {
const [value, setValue] = React.useState<string[]>(['Next.js']);
const anchorRef = React.useRef<HTMLDivElement>(null);
return (
<Combobox items={frameworks} multiple value={value} onValueChange={setValue}>
<ComboboxChips ref={anchorRef}>
<ComboboxValue>
{(items: string[]) =>
items.map((item) => <ComboboxChip key={item}>{item}</ComboboxChip>)
}
</ComboboxValue>
<ComboboxChipsInput placeholder="Add framework…" />
</ComboboxChips>
<ComboboxContent anchor={anchorRef}>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Popup
Trigger the combobox from a button-like ComboboxTrigger instead of an
always-visible input — move ComboboxInput inside ComboboxContent with
showTrigger={false}.
import * as stylex from '@stylexjs/stylex';
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import { space } from '@/lib/constants.stylex';
const fruits = ['Apple', 'Banana', 'Cherry', 'Mango', 'Peach'];
export default function ComboboxPopup() {
return (
<Combobox items={fruits}>
<ComboboxTrigger>
<ComboboxValue placeholder="Select a fruit" />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput
showTrigger={false}
placeholder="Search fruit…"
style={styles.input}
/>
<ComboboxEmpty>No fruit found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
const styles = stylex.create({
input: {
paddingBlock: space.s1,
paddingInline: space.s1,
width: '100%',
},
});
Clear
Use showClear on ComboboxInput to show a button that clears the value.
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
const frameworks = ['Next.js', 'SvelteKit', 'Nuxt', 'Remix', 'Astro'];
export default function ComboboxClear() {
return (
<Combobox items={frameworks} defaultValue="Next.js">
<ComboboxInput showClear placeholder="Search framework…" />
<ComboboxContent>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Groups
Use ComboboxGroup, ComboboxLabel, ComboboxCollection, and
ComboboxSeparator to group related items.
import * as React from 'react';
import {
Combobox,
ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxLabel,
ComboboxList,
ComboboxSeparator,
} from '@/components/ui/combobox';
const groups = [
{ label: 'Fruits', items: ['Apple', 'Banana', 'Cherry'] },
{ label: 'Vegetables', items: ['Carrot', 'Potato', 'Spinach'] },
];
export default function ComboboxGroups() {
return (
<Combobox items={groups}>
<ComboboxInput placeholder="Search produce…" />
<ComboboxContent>
<ComboboxEmpty>No produce found.</ComboboxEmpty>
<ComboboxList>
{groups.map((group, index) => (
<React.Fragment key={group.label}>
{index > 0 && <ComboboxSeparator />}
<ComboboxGroup items={group.items}>
<ComboboxLabel>{group.label}</ComboboxLabel>
<ComboboxCollection>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxCollection>
</ComboboxGroup>
</React.Fragment>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Custom items
Use itemToStringValue when items are objects, and render any content
inside ComboboxItem.
import * as stylex from '@stylexjs/stylex';
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
import { fontSize } from '@/lib/constants.stylex';
import { colors } from '@/lib/tokens.stylex';
interface Framework {
label: string;
value: string;
description: string;
}
const frameworks: Framework[] = [
{
label: 'Next.js',
value: 'next',
description: 'The React framework for the web',
},
{
label: 'SvelteKit',
value: 'sveltekit',
description: 'Web development, streamlined',
},
{
label: 'Nuxt',
value: 'nuxt',
description: 'The intuitive Vue framework',
},
];
export default function ComboboxCustomItems() {
return (
<Combobox
items={frameworks}
itemToStringValue={(framework: Framework) => framework.label}
>
<ComboboxInput placeholder="Search framework…" />
<ComboboxContent>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(framework: Framework) => (
<ComboboxItem key={framework.value} value={framework}>
<div {...stylex.props(styles.row)}>
<span {...stylex.props(styles.title)}>{framework.label}</span>
<span {...stylex.props(styles.description)}>
{framework.description}
</span>
</div>
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
const styles = stylex.create({
row: {
display: 'flex',
flexDirection: 'column',
},
title: {
fontSize: fontSize.sm,
},
description: {
color: colors.mutedForeground,
fontSize: fontSize.xs,
},
});
Disabled
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
const frameworks = ['Next.js', 'SvelteKit', 'Nuxt', 'Remix', 'Astro'];
export default function ComboboxDisabled() {
return (
<Combobox items={frameworks} disabled>
<ComboboxInput placeholder="Search framework…" />
<ComboboxContent>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Auto highlight
Use autoHighlight to highlight the first matching item automatically while
filtering.
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from '@/components/ui/combobox';
const frameworks = ['Next.js', 'SvelteKit', 'Nuxt', 'Remix', 'Astro'];
export default function ComboboxAutoHighlight() {
return (
<Combobox items={frameworks} autoHighlight>
<ComboboxInput placeholder="Search framework…" />
<ComboboxContent>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
API reference
Built on Base UI Combobox. Pass items to the root and it filters as you type out of the box; ComboboxList accepts a render function over the filtered items. All other props are forwarded to the underlying Base UI parts (multiple, value, onValueChange, itemToStringValue, autoHighlight, custom filter, …); see the Base UI Combobox API reference.
ComboboxInput
Text input with a built-in dropdown trigger button.
| Prop | Type | Default | Description |
|---|---|---|---|
showTrigger |
boolean |
true |
Render the built-in dropdown trigger button. Set false when the input lives inside ComboboxContent and a ComboboxTrigger elsewhere anchors the popup. |
showClear |
boolean |
false |
Render a clear button (Base UI Clear) before the trigger. |
style |
StyleXStyles |
— | StyleX styles merged last — always win over the component’s own styles, applied to the wrapper. |
ComboboxContent
| Prop | Type | Default | Description |
|---|---|---|---|
side |
'top' | 'right' | 'bottom' | 'left' |
'bottom' |
|
sideOffset |
number |
6 |
|
align |
'start' | 'center' | 'end' |
'start' |
|
alignOffset |
number |
0 |
|
anchor |
Element | RefObject<Element | null> | (() => Element) |
— | Positions the popup against an element other than the input/trigger, e.g. ComboboxChips. |
style |
StyleXStyles |
— | StyleX styles merged last — always win over the component’s own styles. |
Styling
ComboboxTrigger (select-like popup trigger button), ComboboxChips (chips container, also usable as a popup anchor), ComboboxChip (pill with a built-in remove button), and ComboboxChipsInput (borderless input for inline use inside ComboboxChips) all accept style (StyleXStyles, merged last so caller overrides always win) plus all native props of the element they render.
ComboboxGroup, ComboboxLabel, ComboboxValue, and ComboboxCollection are also exported for grouped and multi-part lists.