Skip to content
Entangle UI v0.13.0

MultiSelect

A dropdown that lets the user pick several values from a flat or grouped list. Selected values surface as inline chips inside the trigger; once the count exceeds maxInlineChips, the rest collapses into a +N more badge so the trigger never grows out of its slot. Supports optional in-dropdown search, a max cap, and a clear-all button.

Live Preview

  • MultiSelect — picking several values from a known set; the chips show the current selection at a glance.
  • Combobox — single value, with typing-as-search.
  • TagInput — multi-value where the entries are free text, not options from a list.
import { MultiSelect } from 'entangle-ui';
import type { MultiSelectOption } from 'entangle-ui';
const options: MultiSelectOption[] = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'svelte', label: 'Svelte' },
];
<MultiSelect
label="Frameworks"
options={options}
value={selected}
onChange={setSelected}
/>;

Basic

// Controlled
const [value, setValue] = useState<string[]>([]);
<MultiSelect options={options} value={value} onChange={setValue} />
// Uncontrolled
<MultiSelect options={options} defaultValue={['react']} />

Sizes

<MultiSelect size="sm" options={options} />
<MultiSelect size="md" options={options} />
<MultiSelect size="lg" options={options} />

Variants

<MultiSelect variant="default" options={options} />
<MultiSelect variant="ghost" options={options} />
<MultiSelect variant="filled" options={options} />

Pass searchable to render a filter input at the top of the dropdown. A custom filterFn overrides the default substring match.

Searchable

<MultiSelect searchable searchPlaceholder="Filter..." options={options} />
// Custom filter
<MultiSelect
searchable
filterFn={(option, query) => option.value.startsWith(query.toLowerCase())}
options={options}
/>

Options can be organised under non-selectable group headers.

Grouped

<MultiSelect
label="Fruits"
options={[
{
label: 'Citrus',
options: [
{ value: 'lemon', label: 'Lemon' },
{ value: 'lime', label: 'Lime' },
],
},
{
label: 'Berries',
options: [
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'blueberry', label: 'Blueberry' },
],
},
]}
/>

max caps the number of selections. Once reached, additional options become un-selectable until the user removes one.

Max

<MultiSelect
label="Pick up to 2"
options={options}
max={2}
helperText="Maximum 2 frameworks"
/>

maxInlineChips controls how many selected chips render in the trigger before the rest collapse into a +N more badge. Set to Infinity to render every chip; 0 shows only the count.

Many chips

<MultiSelect
options={options}
defaultValue={['react', 'vue', 'svelte', 'angular']}
maxInlineChips={2}
/>

By default the dropdown stays open across selections — useful when the user is picking several values in a row. Set closeOnSelect to dismiss after each pick.

<MultiSelect closeOnSelect options={options} />

Error

<MultiSelect
label="Frameworks"
options={options}
error
errorMessage="Pick at least one framework"
required
/>

Use name to render a hidden input with the selected values joined by ,.

<MultiSelect
name="frameworks"
options={options}
value={value}
onChange={setValue}
/>
  • Trigger is a <button> with role="combobox", aria-haspopup="listbox", and aria-expanded.
  • Dropdown is a role="listbox" with aria-multiselectable="true"; each row is a role="option" with aria-selected.
  • Grouped options use role="group" with aria-label.
  • Keyboard: Arrow Up / Down to navigate, Enter / Space to toggle, Escape to close, Home / End for first / last, Backspace removes the trailing chip.
  • aria-invalid is set in the error state; aria-required when required is set.
  • aria-describedby links to helper / error text.
  • Chip remove buttons have aria-label="Remove <label>"; the clear-all button has aria-label="Clear selection".
Prop Type Default Description
value T[] — Controlled list of selected values.
defaultValue T[] — Default selection (uncontrolled).
options Array<MultiSelectOption<T> | MultiSelectOptionGroup<T>> — Options — flat list or grouped.
placeholder string 'Select...' Placeholder shown when nothing is selected.
searchable boolean false Whether to render a search input inside the dropdown.
searchPlaceholder string 'Search...' Placeholder for the search input.
filterFn (option: MultiSelectOption<T>, query: string) => boolean — Custom filter for searchable mode.
emptyMessage string 'No results found' Message shown when search yields no results.
max number — Maximum number of selected items.
maxInlineChips number 3 Cap of inline chips rendered in the trigger before falling back to a `+N more` badge. `Infinity` to render every chip; `0` to show only the count.
size 'sm' | 'md' | 'lg' 'md' Component size.
variant 'default' | 'ghost' | 'filled' 'default' Visual variant.
label string — Label rendered above the trigger.
helperText string — Helper text rendered below.
error boolean false Error state.
errorMessage string — Error message — overrides `helperText` when `error` is true.
disabled boolean false Disable the entire control.
required boolean false Mark the field as required.
clearable boolean false Show a clear-all button when at least one value is selected.
maxDropdownHeight number 240 Maximum dropdown height in pixels.
minDropdownWidth number — Minimum dropdown width in pixels.
closeOnSelect boolean false Close the dropdown after each selection.
name string — Hidden form-input name. Selected values are joined by `,`.
onChange (values: T[]) => void — Selection change handler.
onOpenChange (open: boolean) => void — Open state change handler.
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLButtonElement> — Ref to the trigger button element.
Prop Type Default Description
value * T — Unique value used for selection.
label string — Display label. Falls back to `value` when omitted.
icon ReactNode — Optional icon rendered before the label.
disabled boolean — Whether this option is disabled.
Prop Type Default Description
label * string — Group header label (non-selectable).
options * MultiSelectOption<T>[] — Options inside this group.