Combobox Group
Organizing Combobox items into labelled groups using the ComboboxGroup and ComboboxGroupLabel components in React.
Combobox Group
index.tsx
import {
Combobox,
ComboboxEmpty,
ComboboxGroup,
ComboboxItem,
} from "@ariakit/ui/components/combobox.ariakit.react";
import { matchSorter } from "match-sorter";
import * as React from "react";
import data from "./data.ts";
export default function Example() {
const [value, setValue] = React.useState("");
const deferredValue = React.useDeferredValue(value);
const matches = React.useMemo(() => {
const keys = ["name", "email", "folder"];
const items = matchSorter(data, deferredValue, {
keys,
baseSort: (a, b) => (a.index < b.index ? -1 : 1),
});
return Object.entries(
Object.groupBy(items, (item) => {
if ("folder" in item) return "Files";
return "Members";
}),
);
}, [deferredValue]);
return (
<div className="flex flex-col gap-2">
<Combobox
label="Find records"
autoSelect
autoComplete="both"
placeholder="e.g., John Doe"
inputValue={value}
setInputValue={setValue}
className="w-64"
>
{!matches.length && <ComboboxEmpty />}
{matches.map(([type, items]) => (
<ComboboxGroup key={type} label={type}>
{items.map((item) => (
<ComboboxItem key={item.name} value={item.name} />
))}
</ComboboxGroup>
))}
</Combobox>
</div>
);
}
data.ts
export const members = [
{ name: "John Smith", email: "john@example.com" },
{ name: "Emma Johnson", email: "emma@example.com" },
{ name: "Michael Brown", email: "michael@example.com" },
{ name: "Sarah Davis", email: "sarah@example.com" },
];
export const files = [
{ name: "annual_report.pdf", folder: "Documents" },
{ name: "project_plan.docx", folder: "Documents" },
{ name: "logo.png", folder: "Images" },
{ name: "team_photo.jpg", folder: "Images" },
{ name: "main.js", folder: "Code" },
{ name: "styles.css", folder: "Code" },
{ name: "data.json", folder: "Code" },
{ name: "images_backup.tar.gz", folder: "Archives" },
{ name: "legacy_code.zip", folder: "Archives" },
];
const data = [...members, ...files];
export default data;
Custom Items
index.tsx
import {
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxItemContent,
ComboboxItemDescription,
ComboboxItemLabel,
ComboboxItemSlot,
ComboboxLabel,
ComboboxPopover,
ComboboxProvider,
} from "@ariakit/ui/components/combobox.ariakit.react";
import { matchSorter } from "match-sorter";
import * as React from "react";
import data from "./data.ts";
function getInitials(name: string) {
return name
.split(" ")
.map((n) => n[0])
.join("");
}
export default function Example() {
const [value, setValue] = React.useState("");
const deferredValue = React.useDeferredValue(value);
const matches = React.useMemo(() => {
const keys = ["name", "email", "folder"];
const items = matchSorter(data, deferredValue, {
keys,
baseSort: (a, b) => (a.index < b.index ? -1 : 1),
});
return Object.entries(
Object.groupBy(items, (item) => {
if ("folder" in item) return "Files";
return "Members";
}),
);
}, [deferredValue]);
return (
<div className="flex flex-col gap-2">
<ComboboxProvider inputValue={value} setInputValue={setValue}>
<ComboboxLabel>Find records</ComboboxLabel>
<ComboboxInput
autoSelect
autoComplete="both"
placeholder="e.g., John Doe"
className="w-64"
/>
<ComboboxPopover>
{!matches.length && <ComboboxEmpty />}
{matches.map(([type, items]) => (
<ComboboxGroup key={type} label={type}>
{items.map((item) => (
<ComboboxItem key={item.name} value={item.name}>
<ComboboxItemSlot
$kind="avatar"
$size="md"
$rowSpan={2}
$layer="brand"
$contrast
aria-hidden
>
{getInitials(item.name)}
</ComboboxItemSlot>
<ComboboxItemContent>
<ComboboxItemLabel>{item.name}</ComboboxItemLabel>
<ComboboxItemDescription>
{"email" in item ? item.email : item.folder}
</ComboboxItemDescription>
</ComboboxItemContent>
</ComboboxItem>
))}
</ComboboxGroup>
))}
</ComboboxPopover>
</ComboboxProvider>
</div>
);
}
data.ts
export const members = [
{ name: "John Smith", email: "john@example.com" },
{ name: "Emma Johnson", email: "emma@example.com" },
{ name: "Michael Brown", email: "michael@example.com" },
{ name: "Sarah Davis", email: "sarah@example.com" },
];
export const files = [
{ name: "annual_report.pdf", folder: "Documents" },
{ name: "project_plan.docx", folder: "Documents" },
{ name: "logo.png", folder: "Images" },
{ name: "team_photo.jpg", folder: "Images" },
{ name: "main.js", folder: "Code" },
{ name: "styles.css", folder: "Code" },
{ name: "data.json", folder: "Code" },
{ name: "images_backup.tar.gz", folder: "Archives" },
{ name: "legacy_code.zip", folder: "Archives" },
];
const data = [...members, ...files];
export default data;
Overview
This sample groups combobox options into members and files. Type in the input to filter the groups. Use the arrow keys to move through the results.
The gallery includes the default sample and the Custom Items variant. Each preview runs in an iframe. Expand a file below a preview to read its source.
Components
The sample uses the workspace’s @ariakit/ui Combobox components. Combobox connects the input and popover. ComboboxGroup labels each group, and ComboboxItem renders each result. The Custom Items variant adds avatars and descriptions with ComboboxItemSlot, ComboboxItemContent, ComboboxItemLabel, and ComboboxItemDescription.