Combobox
Combobox composes Base UI’s combobox primitives with Density attributes on inputs and items. Its text input opens and filters the option list, while selected options render through ListItem active state instead of visible selected text.
import { useState } from "react";
import { Combobox } from "density-base-ui";
const projects = [
{ value: "Apollo", label: "Apollo" },
{ value: "Beacon", label: "Beacon" },
{ value: "Nimbus", label: "Nimbus" },
];
export default function ComboboxExample() {
const [project, setProject] = useState(projects[1]);
return (
<Combobox
items={projects}
value={project}
onValueChange={(nextProject) => {
setProject(nextProject as (typeof projects)[number]);
}}
placeholder="Find a project"
/>
);
}Label
import { useState } from "react";
import { Combobox } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxLabelExample() {
const [selectedItem, setSelectedItem] = useState(items[0]);
return (
<Combobox
value={selectedItem}
onValueChange={(item) => setSelectedItem(item as (typeof items)[number])}
items={items}
label="Field label"
placeholder="Search"
/>
);
}Hint
Choose one
import { useState } from "react";
import { Combobox } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxHintExample() {
const [selectedItem, setSelectedItem] = useState(items[0]);
return (
<Combobox
value={selectedItem}
onValueChange={(item) => setSelectedItem(item as (typeof items)[number])}
items={items}
label="Field label"
hint="Choose one"
placeholder="Search"
/>
);
}Error
Choose a project owner.
import { useState } from "react";
import { Combobox } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxErrorExample() {
const [selectedItem, setSelectedItem] = useState(items[0]);
return (
<Combobox
value={selectedItem}
onValueChange={(item) => setSelectedItem(item as (typeof items)[number])}
errorMessage="Choose a project owner."
hint="Choose one."
items={items}
label="Project owner"
placeholder="Search"
/>
);
}Field orientation
The field copy stacks above the input.
The field copy sits beside the input.
import { useState } from "react";
import { Combobox, Separator, View } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxFieldOrientationExample() {
const [verticalItem, setVerticalItem] = useState(items[0]);
const [horizontalItem, setHorizontalItem] = useState(items[0]);
return (
<View align="start" gap="md" padding={false}>
<Combobox
value={verticalItem}
onValueChange={(item) =>
setVerticalItem(item as (typeof items)[number])
}
items={items}
label="Vertical field"
hint="The field copy stacks above the input."
fieldOrientation="vertical"
placeholder="Search"
/>
<Separator />
<Combobox
value={horizontalItem}
onValueChange={(item) =>
setHorizontalItem(item as (typeof items)[number])
}
items={items}
label="Horizontal field"
hint="The field copy sits beside the input."
fieldOrientation="horizontal"
placeholder="Search"
/>
</View>
);
}Placeholder
import { useState } from "react";
import { Combobox } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxPlaceholderExample() {
const [selectedItem, setSelectedItem] = useState(items[0]);
return (
<Combobox
value={selectedItem}
onValueChange={(item) => setSelectedItem(item as (typeof items)[number])}
items={items}
placeholder="Search"
/>
);
}Empty label
import { useState } from "react";
import { Combobox } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxEmptyLabelExample() {
const [selectedItem, setSelectedItem] = useState(items[0]);
return (
<Combobox
value={selectedItem}
onValueChange={(item) => setSelectedItem(item as (typeof items)[number])}
items={items}
emptyLabel="Nothing found"
placeholder="Search"
/>
);
}Input emphasis
import { useState } from "react";
import { Combobox, View } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxEmphasisExample() {
const [selectedItems, setSelectedItems] = useState<
Record<string, (typeof items)[number]>
>({});
const updateSelectedItem = (emphasis: string, item: unknown) => {
setSelectedItems((currentItems) => ({
...currentItems,
[emphasis]: item as (typeof items)[number],
}));
};
return (
<View align="start" gap="md" padding={false}>
<Combobox
value={selectedItems.primary ?? items[0]}
onValueChange={(item) => updateSelectedItem("primary", item)}
items={items}
emphasis="primary"
placeholder="Search"
/>
<Combobox
value={selectedItems.secondary ?? items[0]}
onValueChange={(item) => updateSelectedItem("secondary", item)}
items={items}
emphasis="secondary"
placeholder="Search"
/>
<Combobox
value={selectedItems.outline ?? items[0]}
onValueChange={(item) => updateSelectedItem("outline", item)}
items={items}
emphasis="outline"
placeholder="Search"
/>
<Combobox
value={selectedItems.ghostPrimary ?? items[0]}
onValueChange={(item) => updateSelectedItem("ghostPrimary", item)}
items={items}
emphasis="ghost-primary"
placeholder="Search"
/>
<Combobox
value={selectedItems.ghostSecondary ?? items[0]}
onValueChange={(item) => updateSelectedItem("ghostSecondary", item)}
items={items}
emphasis="ghost-secondary"
placeholder="Search"
/>
<Combobox
value={selectedItems.ghostTertiary ?? items[0]}
onValueChange={(item) => updateSelectedItem("ghostTertiary", item)}
items={items}
emphasis="ghost-tertiary"
placeholder="Search"
/>
</View>
);
}Size
import { useState } from "react";
import { Combobox, View } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxSizeExample() {
const [selectedItems, setSelectedItems] = useState<
Record<string, (typeof items)[number]>
>({});
const updateSelectedItem = (size: string, item: unknown) => {
setSelectedItems((currentItems) => ({
...currentItems,
[size]: item as (typeof items)[number],
}));
};
return (
<View align="start" gap="md" padding={false}>
<Combobox
value={selectedItems["2xs"] ?? items[0]}
onValueChange={(item) => updateSelectedItem("2xs", item)}
items={items}
size="2xs"
placeholder="Search"
/>
<Combobox
value={selectedItems.xs ?? items[0]}
onValueChange={(item) => updateSelectedItem("xs", item)}
items={items}
size="xs"
placeholder="Search"
/>
<Combobox
value={selectedItems.sm ?? items[0]}
onValueChange={(item) => updateSelectedItem("sm", item)}
items={items}
size="sm"
placeholder="Search"
/>
<Combobox
value={selectedItems.md ?? items[0]}
onValueChange={(item) => updateSelectedItem("md", item)}
items={items}
size="md"
placeholder="Search"
/>
<Combobox
value={selectedItems.lg ?? items[0]}
onValueChange={(item) => updateSelectedItem("lg", item)}
items={items}
size="lg"
placeholder="Search"
/>
<Combobox
value={selectedItems.xl ?? items[0]}
onValueChange={(item) => updateSelectedItem("xl", item)}
items={items}
size="xl"
placeholder="Search"
/>
<Combobox
value={selectedItems["2xl"] ?? items[0]}
onValueChange={(item) => updateSelectedItem("2xl", item)}
items={items}
size="2xl"
placeholder="Search"
/>
<Combobox
value={selectedItems["3xl"] ?? items[0]}
onValueChange={(item) => updateSelectedItem("3xl", item)}
items={items}
size="3xl"
placeholder="Search"
/>
</View>
);
}Padding
Combobox adds padding around its popup list by default. Set padding={false} when the list should reach the popup edges. This does not affect the input.
import { useState } from "react";
import { Combobox, View } from "density-base-ui";
const items = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" },
];
export default function ComboboxPaddingExample() {
const [selectedItems, setSelectedItems] = useState<
Record<string, (typeof items)[number]>
>({});
const updateSelectedItem = (paddingState: string, item: unknown) => {
setSelectedItems((currentItems) => ({
...currentItems,
[paddingState]: item as (typeof items)[number],
}));
};
return (
<View align="start" gap="md" padding={false}>
<Combobox
value={selectedItems.unpadded ?? items[0]}
onValueChange={(item) => updateSelectedItem("unpadded", item)}
items={items}
padding={false}
placeholder="Search"
/>
<Combobox
value={selectedItems.padded ?? items[0]}
onValueChange={(item) => updateSelectedItem("padded", item)}
items={items}
placeholder="Search"
/>
</View>
);
}| Prop | Values | Required | Default | Behavior | Description |
|---|---|---|---|---|---|
emphasis | primary, secondary, outline, ghost-primary, ghost-secondary, ghost-tertiary | Not required | — | Attribute: data-dn-emphasis | — |
emptyLabel | React.ReactNode | Not required | "No results" | — | — |
errorMessage | React.ReactNode | Not required | — | — | — |
fieldOrientation | vertical, horizontal | Not required | — | — | — |
hint | React.ReactNode | Not required | — | — | — |
id | string | Not required | — | — | The id of the component. |
items | (readonly any[] | readonly import("@base-ui/react/internals/resolveValueLabel").Group<any>[]) & ComboboxItem[] | Required | — | — | The items to be displayed in the list. Can be either a flat array of items or an array of groups with items. |
label | React.ReactNode | Not required | — | — | — |
padding | false, true | Not required | true | Attribute: data-dn-padding | Controls the popup surface inset. |
placeholder | string | Not required | — | — | — |
size | 2xs, xs, sm, md, lg, xl, 2xl, 3xl | Not required | — | Attribute: data-dn-size | — |
This component also accepts props from native APIs. They are passed through and intentionally kept out of this focused Density API table.