Ariakit
/

Combobox with Tabs

Organizing Combobox with Tab components that support mouse, keyboard, and screen reader interactions. The UI remains responsive by using React.startTransition.

import groupBy from "lodash-es/groupBy.js";
import { matchSorter } from "match-sorter";
import { useId, useMemo, useState } from "react";
import {
ComboboxPanel,
ComboboxTab,
ComboboxTabList,
} from "./combobox.tsx";
import { flatPages, pages } from "./pages.ts";
import "./style.css";
const categories = ["All", ...Object.keys(pages)];
function getTabId(category: string, prefix: string) {
return `${prefix}/${category}`;
}
function getCategory(tabId: string, prefix: string) {
return tabId.replace(`${prefix}/`, "");
}
export default function Example() {
const prefix = useId();
const [searchValue, setSearchValue] = useState("");
const [tabId, setTabId] = useState(getTabId("Components", prefix));
const matches = useMemo(() => {
const keys = ["label", "path"];
const allMatches = matchSorter(flatPages, searchValue, { keys });
const groups = groupBy(allMatches, "category");
groups.All = allMatches;
return groups;
}, [searchValue]);
const currentPages = matches[getCategory(tabId, prefix)] || [];
return (
defaultTabId={tabId}
onTabChange={setTabId}
onSearch={setSearchValue}
>
<Combobox placeholder="Search pages" />
<ComboboxPopover aria-label="Pages">
<ComboboxTabList aria-label="Categories">
{categories.map((category) => {
const currentPages = matches[category];
return (
<ComboboxTab
key={category}
id={getTabId(category, prefix)}
disabled={!currentPages?.length}
>
{category}
<span className="count">{currentPages?.length || 0}</span>
</ComboboxTab>
);
})}
</ComboboxTabList>
<ComboboxPanel>
{!currentPages.length && (
<div className="no-results">
No pages found for &quot;<strong>{searchValue}</strong>
&quot;
</div>
)}
{currentPages.map((page, i) => (
key={page.path + i}
render={<a href={page.path} target="_blank" rel="noreferrer" />}
>
{page.label}
))}
</ComboboxPanel>
);
}

Stay tuned

Join 1,000+ subscribers and receive monthly tips & updates on new Ariakit content.

No spam. Unsubscribe anytime. Read latest issue