Skip to main content
Vuetify0 v1.0 is here
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

Single

A headless provider for exclusive single-selection — selecting an item automatically deselects the previously selected one. Drives tabs, segmented controls, theme pickers, and other exclusive-choice UIs.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

StableRenderlessIntermediateJun 25, 2026
Note

Single is a headless single-selection state provider — it tracks the selected item but ships no role, keyboard navigation, or focus management. For an accessible radio group with role="radio" and arrow-key navigation, use Radio, which is built on the same single-selection logic.

Usage

The Single component is a specialization of Selection that enforces single-selection behavior. When an item is selected, any previously selected item is automatically deselected.

Selected:

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

  const selected = shallowRef<string>()
</script>

<template>
  <Single.Root v-model="selected">
    <div class="flex flex-col gap-2">
      <Single.Item
        v-for="size in ['small', 'medium', 'large']"
        :key="size"
        v-slot="{ attrs }"
        :value="size"
      >
        <button
          v-bind="attrs"
          class="px-3 py-1.5 border rounded text-left text-sm bg-surface border-divider data-[selected]:bg-surface-tint data-[selected]:border-primary"
        >
          {{ size }}
        </button>
      </Single.Item>
    </div>
  </Single.Root>

  <p class="mt-4">Selected: {{ selected }}</p>
</template>

Anatomy

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

<template>
  <Single.Root>
    <Single.Item />
  </Single.Root>
</template>

Examples

Billing-period segmented control

A Monthly/Yearly segmented control built on Single.Root with mandatory. Each Single.Item is a billing period; selecting one auto-deselects the other, and mandatory blocks clicking the active segment off, so a period is always chosen. The selected value flows straight through the Root’s v-model, and the live price card below it reacts to that one value — switching to Yearly drops the per-month price and reveals the savings badge.

Single ships no roles, keyboard handling, or focus management — it is a pure selection-state provider, so both Single.Root and Single.Item are renderless. That is why the segment binds the item’s slot attrs directly onto its own <button>: attrs carries the onClick toggle plus the data-selected / aria-selected state. Styling keys off data-selected (the active label darkens) and a sliding indicator is positioned with a translateX derived from the selected index — the example owns its own semantics and visuals on top of the provider’s state.

Reach for Single when you are building an exclusive-choice control you want to style yourself — segmented toggles, theme pickers, view switchers. If you need an accessible, form-ready radio group with role="radiogroup", arrow-key navigation, and a hidden input, use Radio instead; for multi-select, use Selection. The underlying logic is createSingle.

FileRole
usePlanPricing.tsOwns the selected period and derives the per-month price, billed amount, and savings
BillingToggle.vueRenders the Single segmented control with a sliding data-selected indicator
billing-toggle.vueWires the composable to the toggle and renders the live price card

Pro plan

$15/ month

$15 billed monthly

Accessibility

Single is a headless state provider, not a complete interactive widget. It manages which item is selected and exposes that state on each item’s slot attrs; it does not ship a role, keyboard navigation, or focus management.

  • Single.Root exposes aria-multiselectable="false".

  • Single.Item exposes aria-selected and aria-disabled, plus data-selected and data-disabled for styling.

This is listbox/tab-style selection state. For an accessible radio group — role="radiogroup", role="radio", arrow-key navigation, and roving tabindex — use Radio, which composes the same single-selection logic. When you bind attrs to your own element, you are responsible for supplying the appropriate role and keyboard handlers for the pattern you are building.

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for all variations of the Single component.
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/