MultiSelect
Multi-value picker with a fixed-height segmented trigger; selected values render as removable chips that collapse to a +N badge, and the dropdown lists every option with a search field.
role="combobox" trigger with an aria-multiselectable listbox; options stay in the list marked selected; Backspace in the empty search removes the last chip.
Rendered as a segmented control — chips sit in a raised value tile and the
chevron in its own slot inside the tinted track, matching the other inputs.
The trigger keeps a fixed height: chips that don’t fit collapse into a
+N badge instead of wrapping. Opening it reveals a search field — the Cynosure SearchInput, pinned to the
top while the list scrolls — and the full option list; every item stays in the
list (marked with a checkmark) and toggles on click, so nothing becomes
unreachable.
import { MultiSelect } from '@arshad-shah/cynosure-react';
const items = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'solid', label: 'Solid' },
{ value: 'qwik', label: 'Qwik' },
];
export default function Example() {
return (
<div style={{ width: '320px' }}>
<MultiSelect
items={items}
defaultValue={['react', 'svelte']}
placeholder="Pick frameworks"
aria-label="Frameworks"
/>
</div>
);
}
Three sizes are available: sm, md (default), and lg.
import { MultiSelect } from '@arshad-shah/cynosure-react';
const items = [
{ value: 'ie', label: 'Ireland' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'fr', label: 'France' },
{ value: 'de', label: 'Germany' },
];
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', width: '320px' }}>
<MultiSelect aria-label="Small" size="sm" items={items} defaultValue={['ie']} />
<MultiSelect aria-label="Medium" size="md" items={items} defaultValue={['ie', 'uk']} />
<MultiSelect aria-label="Large" size="lg" items={items} defaultValue={['ie', 'uk', 'fr']} />
</div>
);
}
Maximum selected
Section titled “Maximum selected”Set maxSelected to cap how many values can be added. Items past the cap render as disabled in the listbox.
import { MultiSelect } from '@arshad-shah/cynosure-react';
const items = [
{ value: 'a', label: 'Apples' },
{ value: 'b', label: 'Bananas' },
{ value: 'c', label: 'Cherries' },
{ value: 'd', label: 'Dragonfruit' },
{ value: 'e', label: 'Elderberries' },
];
export default function Example() {
return (
<div style={{ width: '320px' }}>
<MultiSelect
aria-label="Pick up to 2 fruits"
items={items}
maxSelected={2}
placeholder="Pick up to 2"
/>
</div>
);
}
Disabled
Section titled “Disabled”import { MultiSelect } from '@arshad-shah/cynosure-react';
const items = [
{ value: 'r', label: 'Red' },
{ value: 'g', label: 'Green' },
{ value: 'b', label: 'Blue' },
];
export default function Example() {
return (
<div style={{ width: '320px' }}>
<MultiSelect aria-label="Colors" items={items} defaultValue={['r', 'b']} disabled />
</div>
);
}
Invalid
Section titled “Invalid”Set invalid to mark the field for validation feedback.
import { MultiSelect } from '@arshad-shah/cynosure-react';
const items = [
{ value: 'owner', label: 'Owner' },
{ value: 'editor', label: 'Editor' },
{ value: 'viewer', label: 'Viewer' },
];
export default function Example() {
return (
<div style={{ width: '320px' }}>
<MultiSelect
aria-label="Roles"
items={items}
invalid
required
placeholder="Pick at least one"
/>
</div>
);
}
Accessibility
Section titled “Accessibility”- The popup uses
role="listbox"witharia-multiselectable="true"androle="option"items. - The internal
<input>keeps focus while typing filters the listbox. Backspaceon an empty input removes the most recently selected value.ArrowDownopens the popover;Escapecloses it without losing focus.- Each tag’s remove button has an accessible label of the form
Remove {label}.
Recipes
Section titled “Recipes”- Provide an
aria-label(orlabel) when the field has no visible caption. - Use
emptyStateto render a custom node when the filtered list is empty. - Set
maxSelectedfor tag-limited filters; the listbox surfaces the cap viaaria-disabled.