Ariakit
/

select-combobox-virtualized

Country
import * as Ariakit from "@ariakit/react";
import { SelectRenderer } from "@ariakit/react-core/select/select-renderer";
import type { SelectRendererItem } from "@ariakit/react-core/select/select-renderer";
import deburr from "lodash-es/deburr.js";
import groupBy from "lodash-es/groupBy.js";
import kebabCase from "lodash-es/kebabCase.js";
import { matchSorter } from "match-sorter";
import { startTransition, useEffect, useState } from "react";
import { countries } from "./countries.ts";
import "./style.css";
function getItem(country: string) {
return {
id: `item-${kebabCase(country)}`,
value: country,
children: country,
};
}
function groupItems(items: ReturnType<typeof getItem>[]) {
const groups = groupBy(items, (item) => deburr(item.value?.at(0)));
return Object.entries(groups).map(([label, items]) => {
return {
id: `group-${label.toLowerCase()}`,
label,
itemSize: 40,
paddingStart: 44,
items,
} satisfies SelectRendererItem;
});
}
const defaultItems = countries.map(getItem);
export default function Example() {
const [searchValue, setSearchValue] = useState("");
const [matches, setMatches] = useState(() => groupItems(defaultItems));
const combobox = Ariakit.useComboboxStore({
value: searchValue,
setValue: setSearchValue,
});
const select = Ariakit.useSelectStore({
});
const selectValue = Ariakit.useStoreState(select, "value");
useEffect(() => {
startTransition(() => {
const items = matchSorter(countries, searchValue);
setMatches(groupItems(items.map(getItem)));
});
}, [searchValue]);
return (
<>
<div className="wrapper">
<Ariakit.Select store={select} className="button">
<span className="select-value">
{selectValue || "Select a country"}
</span>
store={select}
gutter={4}
className="popover"
>
<div className="combobox-wrapper">
store={combobox}
placeholder="Search..."
className="combobox"
/>
</div>
<SelectRenderer store={select} items={matches} gap={8} overscan={1}>
{({ label, ...item }) => (
<SelectRenderer
key={item.id}
className="group"
overscan={1}
{...item}
render={(props) => (
<Ariakit.SelectGroup {...props}>
<Ariakit.SelectGroupLabel className="group-label">
{label}
{props.children}
)}
>
{({ value, ...item }) => (
key={item.id}
{...item}
className="select-item"
>
<span className="select-item-value">{value}</span>
)}
</SelectRenderer>
)}
</SelectRenderer>
</div>
</>
);
}

Stay tuned

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

No spam. Unsubscribe anytime. Read latest issue