Skip to main content
Vuetify0 is now in beta!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Select

Headless dropdown select with single and multi-selection, keyboard navigation, and native popover positioning.

Usage

The Select component provides a compound pattern for building accessible dropdown selects. It supports v-model for both single values and arrays (multi-select mode).

Basic Select

A single-select color dropdown with placeholder text and selected value display.

Selected: None

Anatomy

vue
<script setup lang="ts">
  import { Select } from '@vuetify/v0'
</script>

<template>
  <Select.Root>
    <Select.Activator>
      <Select.Value />
      <Select.Placeholder />

      <Select.Cue />
    </Select.Activator>

    <Select.Content>
      <Select.Item />
    </Select.Content>
  </Select.Root>
</template>

Architecture

The Root creates selection, virtual focus, and popover contexts. The Activator serves as the combobox trigger with keyboard event handling. Content renders via the native popover API with CSS anchor positioning. Each Item registers with the selection context and provides data attributes for styling.

Select Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Select Architecture

Examples

Disabled States

Both individual items and the entire select can be disabled. Disabled items are skipped by virtual focus keyboard navigation. The disabled prop on Root prevents the dropdown from opening.

Selected: None

Multi-Select

Set multiple on Root to enable multi-selection. The dropdown stays open after each selection. v-model binds to an array of item values (the value prop of each selected item). The Value slot receives selectedValues for rendering chips, tags, or comma-separated text.

Selected: None

Recipes

Form Submission

Set name on Root to auto-render hidden inputs for form submission — one per selected value in multi-select mode:

vue
<template>
  <Select.Root v-model="value" name="color">
    <!-- ... -->
  </Select.Root>
</template>

Mandatory Selection

Use mandatory to prevent deselecting the last item, or mandatory="force" to auto-select the first item on mount:

vue
<template>
  <Select.Root v-model="value" mandatory="force">
    <!-- First non-disabled item is selected automatically -->
  </Select.Root>
</template>

Understanding id vs value

Each Select.Item has two key props:

  • id — Internal key for the selection registry. Used for virtual focus, ARIA attributes, and ticket lookup.

  • value — The value synced to v-model. This is what Select.Value’s selectedValue slot prop exposes.

The model always receives the value prop, not the id. When id and value differ, use the selectedValue slot prop to look up a display label:

vue
<script setup lang="ts">
  import { Select } from '@vuetify/v0'
  import { shallowRef } from 'vue'

  const language = shallowRef('en')

  const languages = [
    { id: 'en', label: 'English' },
    { id: 'es', label: 'Spanish' },
    { id: 'fr', label: 'French' },
  ]
</script>

<template>
  <Select.Root v-model="language" mandatory>
    <Select.Activator>
      <Select.Value v-slot="{ selectedValue }">
        {{ languages.find(l => l.id === selectedValue)?.label }}
      </Select.Value>
      <Select.Cue />
    </Select.Activator>

    <Select.Content>
      <Select.Item
        v-for="lang in languages"
        :id="lang.id"
        :key="lang.id"
        :value="lang.id"
      >
        {{ lang.label }}
      </Select.Item>
    </Select.Content>
  </Select.Root>
</template>
Tip

When id and value are the same (the common case), Select.Value displays the model value directly — no lookup needed.

Pre-Selected Values

Select supports pre-selected values via v-model or :model-value. The Select.Value component shows the model value immediately, even before the dropdown has been opened. Select.Placeholder automatically hides when a model value is present:

vue
<template>
  <!-- "Banana" shows immediately, no dropdown open needed -->
  <Select.Root v-model="fruit" mandatory>
    <Select.Activator>
      <Select.Value v-slot="{ selectedValue }">{{ selectedValue }}</Select.Value>
      <Select.Placeholder>Pick a fruit…</Select.Placeholder>
    </Select.Activator>

    <Select.Content>
      <Select.Item value="Apple">Apple</Select.Item>
      <Select.Item value="Banana">Banana</Select.Item>
    </Select.Content>
  </Select.Root>
</template>

Custom Positioning

Control dropdown placement with CSS anchor positioning props on Content:

vue
<template>
  <Select.Content position-area="top" position-try="flip-block">
    <!-- Dropdown appears above the activator -->
  </Select.Content>
</template>

Data Attributes

Style interactive states without slot props:

AttributeValuesComponent
data-selectedtrueItem
data-highlighted""Item
data-disabledtrueItem
data-opentrueActivator
data-state"open" / "closed"Cue

Accessibility

The Select implements the WAI-ARIA Combobox↗︎ pattern with a listbox popup.

ARIA Attributes

AttributeValueComponent
rolecomboboxActivator
rolelistboxContent
roleoptionItem
aria-expandedtrue / falseActivator
aria-haspopuplistboxActivator
aria-controlslistbox IDActivator
aria-selectedtrue / falseItem
aria-disabledtrueItem (when disabled)
aria-multiselectabletrueContent (when multiple)

Keyboard Navigation

KeyAction
Enter / SpaceOpen dropdown, or select highlighted item
ArrowDownOpen dropdown, or move highlight down
ArrowUpOpen dropdown, or move highlight up
HomeMove highlight to first item
EndMove highlight to last item
EscapeClose dropdown
TabClose dropdown and move focus
Was this page helpful?

Ctrl+/