Components / Forms

MultiSelect

A multi-select listbox with removable chips and overflow.

Preview

Choose teams
0 teams selected:
Choose teams
0 teams selected:
Choose teams
0 teams selected:

Install

Run in your project
Package manager
npx @getweini/cli@latest add multi-select

Use cases

Multiple regions

Choose several regions and submit repeated form values.

Compact tag filters

Limit visible chips while retaining a complete selection summary.

Usage example

Vue
<script setup lang="ts">
import { ref } from 'vue'
import MultiSelect from './components/ui/multi-select/MultiSelect.vue'
import MultiSelectTrigger from './components/ui/multi-select/MultiSelectTrigger.vue'
import MultiSelectValue from './components/ui/multi-select/MultiSelectValue.vue'
import MultiSelectContent from './components/ui/multi-select/MultiSelectContent.vue'
import MultiSelectOption from './components/ui/multi-select/MultiSelectOption.vue'
const regions = ref<string[]>([])
const messages = {
  listboxLabel: 'Region options',
  empty: 'No regions available',
  clear: 'Clear',
  clearSelection: 'Clear all regions',
  changeSelection: 'Change regions',
  removeSelection: (label: string) => 'Remove ' + label,
  overflow: (count: number) => '+' + count,
  selectionSummary: (labels: readonly string[]) => labels.length + ' regions selected: ' + labels.join(', '),
}
</script>

<template>
  <label id="regions-label" for="regions">Regions</label>
  <MultiSelect id="regions" aria-labelledby="regions-label" v-model="regions" :messages="messages">
    <MultiSelectTrigger><MultiSelectValue placeholder="Choose regions" /></MultiSelectTrigger>
    <MultiSelectContent>
      <MultiSelectOption value="LU">Luxembourg</MultiSelectOption>
      <MultiSelectOption value="BE">Belgium</MultiSelectOption>
    </MultiSelectContent>
  </MultiSelect>
</template>

More examples

Region picker

All selection and removal text belongs to the application.

Region picker
<script setup lang="ts">
import { ref } from 'vue'
import MultiSelect from './components/ui/multi-select/MultiSelect.vue'
const regions = ref<string[]>([])
const options = [{ label: 'Luxembourg', value: 'LU' }, { label: 'Belgium', value: 'BE' }]
const messages = {
  listboxLabel: 'Regions', empty: 'No regions', clear: 'Clear', clearSelection: 'Clear regions',
  changeSelection: 'Change regions', removeSelection: (label: string) => 'Remove ' + label,
  selectionSummary: (labels: readonly string[]) => labels.length + ' regions: ' + labels.join(', '),
  overflow: (count: number) => '+' + count,
}
</script>
<template>
  <label for="regions">Regions</label>
  <MultiSelect id="regions" v-model="regions" :options="options" :messages="messages" name="regions" placeholder="Choose regions" />
</template>

Compact filters

The visible chip limit does not limit selected values.

Compact filters
<script setup lang="ts">
import { ref } from 'vue'
import MultiSelect from './components/ui/multi-select/MultiSelect.vue'
const tags = ref<string[]>(['design'])
const options = [{ label: 'Design', value: 'design' }, { label: 'Engineering', value: 'engineering' }]
const messages = {
  listboxLabel: 'Tags', empty: 'No tags', clear: 'Clear', clearSelection: 'Clear tags',
  changeSelection: 'Change tags', removeSelection: (label: string) => 'Remove ' + label,
  selectionSummary: (labels: readonly string[]) => labels.length + ' tags: ' + labels.join(', '),
  overflow: (count: number) => '+' + count,
}
</script>
<template>
  <label for="tags">Tags</label>
  <MultiSelect id="tags" v-model="tags" :options="options" :messages="messages" :max-visible-chips="2" clearable />
</template>

Key API

The most useful props, models, slots, events, and methods for this component.

Key API for MultiSelect
NameTypeDefault or requirement
v-modelT[][]
open / defaultOpenbooleanfalse
maxVisibleChipsnumber1
messagesMultiSelectMessagesrequired
clearable / required / invalidbooleanfalse

Enter or Space toggles the focused option. Named fields submit repeated values; read them with FormData.getAll(name).

Implementation notes

  • Named controls submit repeated values; read them with FormData.getAll(name).
  • maxVisibleChips changes the trigger display only, not the selected model.

Accessibility and localization

  • Localize every messages field, including chip removal and the full selection summary.
Weini UIDesign system · Vue component library · Free and public