motif svelteArc

Multi Select ported

A choice field that collects several values as chips.

A labelled trigger that opens a multi-choice menu. Picks collect as chips with an overflow count, and a clear button empties the field. Built on Bits UI Combobox multiple mode with ARC styling verbatim.

Live specimen

Loading demo…

Guidance

When to use

  • Form fields where several options apply at once, such as tags or team members.
  • Compact filters where the selection must stay visible as chips.
  • Menus that need accessible multi-select semantics with keyboard navigation.

When not to use

  • Use select or combobox when only one value can be chosen.
  • Use chip-group when every choice should stay visible as toggleable filters.
  • Use checkbox lists when each option needs its own visible label and description.

Installation

pnpm add sveltearc

Usage

<script lang="ts">
  import { MultiSelect } from '$lib/components/multi-select';

  let topics = $state(['svelte']);

  const options = [
    { value: 'svelte', label: 'Svelte' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue', disabled: true }
  ];
</script>

<MultiSelect
  label="Topics"
  bind:value={topics}
  {options}
  description="Followed topics for the weekly digest."
/>

Variants & Examples

Controlled with Description

Two-way binding via bind:value with helper text below the field.

<MultiSelect
  label="Topics"
  bind:value={topics}
  options={topicOptions}
  description="Followed topics for the weekly digest."
/>

Overflow Count

Chips beyond maxVisible fold behind a "+N" count.

<MultiSelect
  label="Topics"
  bind:value={topics}
  options={topicOptions}
  maxVisible={1}
/>

Disabled

Disables the whole field, or individual options via disabled on the option.

<MultiSelect
  label="Locked Topics"
  value={['svelte']}
  disabled
  options={topicOptions}
/>

API Reference

PropTypeDefaultDescription
labelstring–Accessible name of the field, rendered as the visible label.
optionsMultiSelectOption[]–Array of { value: string; label: string; disabled?: boolean } items in list order.
valuestring[]undefinedControlled selection; supports two-way bind:value.
defaultValuestring[][]Initial selection when uncontrolled.
onValueChange(value: string[]) => void–Callback fired whenever the selection changes.
openbooleanundefinedControlled open state of the menu; supports two-way bind:open.
onOpenChange(open: boolean) => void–Callback fired when the menu opens or closes.
placeholderstring'Select options'Placeholder copy shown when nothing is selected.
descriptionstring–Helper copy rendered below the field.
maxVisiblenumber2Chips shown before the rest fold behind a "+N" count.
disabledbooleanfalseWhether the whole field is disabled.
classstring–Additional CSS class applied to the field wrapper.

Keyboard Interactions

KeyAction
Enter / SpaceOpens the menu from the trigger, or picks the highlighted option when open.
ArrowDown / ArrowUpMoves the highlight between enabled options.
EscapeCloses the menu without changing the selection.

Accessibility

  • Built on Bits UI Combobox multiple mode: the menu carries role="listbox" with aria-multiselectable, options carry role="option" with aria-selected.
  • The trigger announces the selection through an aria-labelledby pair of visible label and screen-reader value text.
  • Highlight is tracked for the data-active style hook without taking focus from the trigger.
  • Disabled options are exposed with aria-disabled and skipped by selection.

Motion

Phase 1 still-state: chips and the overflow count render at their resting end-state with no slot-spring travel; the menu mounts when open with no enter/exit travel; the check renders fully drawn. Phase 2 wires the chip slot springs, overflow count roll, checkbox path draw, and menu spring. Reduced motion keeps the same end-states with instant transitions.

Notes for AI

  • Pick when several values can be chosen and should read back as chips.
  • Two-way binding is available via bind:value={selected}.
  • Control chip overflow with maxVisible; the rest fold behind a "+N" count.

Source of truth: registry/components/multi-select/multi-select.tsx