Autocomplete: Multiple values
With multiple, the Autocomplete keeps several values: value is an array of ids, each selected option shows as a tag in the trigger, and the popup stays open as you pick, so you can choose several in a row.
Selected: accessibility, forms
import { useState } from "react";
import { Autocomplete, type OptionValue } from "slotsmith/autocomplete";
import { topics } from "../shared/options";
export default function Multiple() {
const [topicIds, setTopicIds] = useState<OptionValue[]>(["accessibility", "forms"]);
return (
<div style={{ display: "grid", gap: "1rem", maxWidth: 360 }}>
<Autocomplete
// `multiple` makes value an array and keeps the popup open on each pick.
multiple
options={topics}
optionDisabled={(topic) => !!topic.archived}
value={topicIds}
onChange={setTopicIds}
// Three tags show; the rest collapse into "+N".
maxTags={3}
aria-label="Topics"
/>
<p>{topicIds.length === 0 ? "Nothing selected." : `Selected: ${topicIds.join(", ")}`}</p>
</div>
);
}export type Country = { code: string; name: string };
/** Sorted by name, as a picker shows them. */
export const countries: Country[] = [
{ code: "ar", name: "Argentina" },
{ code: "au", name: "Australia" },
{ code: "br", name: "Brazil" },
{ code: "ca", name: "Canada" },
{ code: "eg", name: "Egypt" },
{ code: "fr", name: "France" },
{ code: "de", name: "Germany" },
{ code: "in", name: "India" },
{ code: "jp", name: "Japan" },
{ code: "jo", name: "Jordan" },
{ code: "ke", name: "Kenya" },
{ code: "mx", name: "Mexico" },
{ code: "ma", name: "Morocco" },
{ code: "nl", name: "Netherlands" },
{ code: "no", name: "Norway" },
{ code: "pt", name: "Portugal" },
{ code: "sa", name: "Saudi Arabia" },
{ code: "za", name: "South Africa" },
{ code: "es", name: "Spain" },
{ code: "se", name: "Sweden" },
{ code: "tr", name: "Türkiye" },
{ code: "ae", name: "United Arab Emirates" },
{ code: "gb", name: "United Kingdom" },
{ code: "us", name: "United States" },
];
/** `id` and `label` are the names the autocomplete reads by default, so topics need no getters. */
export type Topic = { id: string; label: string; archived?: boolean };
export const topics: Topic[] = [
{ id: "accessibility", label: "Accessibility" },
{ id: "animation", label: "Animation" },
{ id: "caching", label: "Caching" },
{ id: "design-systems", label: "Design systems" },
{ id: "forms", label: "Forms" },
{ id: "i18n", label: "Internationalisation" },
{ id: "performance", label: "Performance" },
{ id: "rtl", label: "Right-to-left" },
{ id: "server-components", label: "Server components" },
{ id: "state", label: "State" },
{ id: "testing", label: "Testing" },
{ id: "typescript", label: "TypeScript" },
{ id: "legacy", label: "Legacy browsers", archived: true },
];
/** A country with the region it is listed under; a `disabled` one stays in the list but cannot be picked. */
export type RegionCountry = Country & { region: string; disabled?: boolean };
/** A short list grouped by region. Groups show in the order of their first option, so the regions come in this order. */
export const countriesByRegion: RegionCountry[] = [
{ code: "de", name: "Germany", region: "Europe" },
{ code: "fr", name: "France", region: "Europe" },
{ code: "es", name: "Spain", region: "Europe" },
{ code: "ge", name: "Georgia", region: "Europe" },
{ code: "dz", name: "Algeria", region: "Africa" },
{ code: "eg", name: "Egypt", region: "Africa" },
{ code: "ng", name: "Nigeria", region: "Africa" },
{ code: "ne", name: "Niger", region: "Africa", disabled: true },
{ code: "jp", name: "Japan", region: "Asia" },
{ code: "sg", name: "Singapore", region: "Asia" },
{ code: "sa", name: "Saudi Arabia", region: "Asia" },
{ code: "sy", name: "Syria", region: "Asia" },
];Open the picker and press Backspace with the search box empty: the last tag goes. Clicking a selected option again removes it too.
Value and onChange
multiple changes the type of the selection props, so neither mode can be given the other’s shape. In single mode, value is an id or null and onChange receives (id, option). In multiple mode, value is an array of ids and onChange receives (ids, options), the options in the same order as the ids. An option is undefined only for an id no option has been seen for; selected supplies those.
Tags
maxTagssets how many tags show (2 by default); the rest collapse into a count read from themorelabel, “+2”. The demo shows three.- Each tag has a remove button named by the
removelabel, “Remove Forms”. TheTagslot replaces the whole tag. - The clear button removes every value at once.
Picking and removing from the keyboard
- Enter on a highlighted option adds it, or removes it if it is already selected. The popup stays open; set
closeOnSelectto close it after each pick. - Backspace in the empty search box removes the last tag. With text in the search box it deletes text as usual.
- The listbox has
aria-multiselectable="true", and each option’saria-selectedfollows the selection.
Disabled options
optionDisabled marks options that stay visible but cannot be picked, like the archived topic in the demo. They get aria-disabled="true", the arrow keys skip them, and a click does nothing.