Switch
A switch for on/off state or multi-selection groups with tri-state support.
Usage
Anatomy
<script setup lang="ts">
import { Switch } from '@vuetify/v0'
</script>
<template>
<Switch.Root>
<Switch.Track>
<Switch.Thumb />
</Switch.Track>
<Switch.HiddenInput />
</Switch.Root>
<Switch.Group>
<Switch.SelectAll>
<Switch.Track>
<Switch.Thumb />
</Switch.Track>
</Switch.SelectAll>
<Switch.Root>
<Switch.Track>
<Switch.Thumb />
</Switch.Track>
</Switch.Root>
</Switch.Group>
</template>Examples
Toggle settings and press Save to capture the current selection.
Recipes
Form Integration
Pass the name prop on Switch.Root and a hidden native <input type="checkbox"> is rendered automatically — no Switch.HiddenInput placement is required. The input is visually hidden, inert, and tabindex="-1", so it only participates in FormData submission:
<template>
<Switch.Root name="notifications" value="on">
<Switch.Track>
<Switch.Thumb />
</Switch.Track>
</Switch.Root>
</template>Switch.HiddenInput is exported as an internal building block for custom layouts, but auto-rendering via name is the only supported form integration path — placing Switch.HiddenInput as a child of a Switch.Root that already has a name will produce two hidden inputs.
Styling with Data Attributes
Switch subcomponents expose data attributes for CSS styling without conditional classes. Switch.Root and Switch.SelectAll emit both data-state and data-disabled, while Switch.Track and Switch.Thumb emit only data-state (they inherit disabled styling from the Root ancestor):
| Attribute | Values | Components |
|---|---|---|
data-state | checked, unchecked, indeterminate | Root, SelectAll, Track, Thumb |
data-disabled | true | Root, SelectAll |
<template>
<Switch.Root class="data-[disabled]:opacity-50">
<Switch.Track class="bg-gray-300 transition-colors data-[state=checked]:bg-primary">
<Switch.Thumb />
</Switch.Track>
</Switch.Root>
</template>Switch.Thumb stays visible in every state and emits data-state (checked / unchecked / indeterminate), so a sliding transform can animate directly between the off and on positions — for example translate-x-1 data-[state=checked]:translate-x-6. Pair it with a transition-transform on the thumb and a transition-colors on the Switch.Track for the rail.
Accessibility
The Switch.Root component renders as a button and handles all ARIA attributes automatically:
role="switch"for proper semanticsaria-checkedreflects state (true,false, or"mixed")aria-disabledwhen switch is disabledaria-labelfrom thelabelproptabindex="0"for keyboard focus (removed when disabled)Space key toggles the switch (Enter works when rendered as button)
For custom implementations, use renderless mode and bind the attrs slot prop to your element:
<template>
<Switch.Root v-slot="{ attrs }" renderless>
<div v-bind="attrs">
<!-- Custom switch visual -->
</div>
</Switch.Root>
</template>FAQ
Use Switch for settings that take immediate effect, like toggling a feature on or off (WiFi, notifications, dark mode). Use Checkbox for selections that are committed later — form submissions, multi-select lists, and “I agree” confirmations. The ARIA roles (switch vs checkbox) communicate this intent to assistive technology.
Switch.Root only renders the hidden native input when a name prop is set. Without name, the switch is purely visual and won’t appear in FormData. Add name="myField" (and optionally value) to participate in form submission.
Drive it off the data-state attribute — no JavaScript event handling needed. Apply a transition-transform to Switch.Thumb and slide it with the data-[state=checked]: variant (class="transition-transform translate-x-1 data-[state=checked]:translate-x-6"), and add a transition-colors to Switch.Track to shift the rail background (class="transition-colors bg-gray-300 data-[state=checked]:bg-primary"). The data attribute flip drives both.
Yes. Switch.Track and Switch.Thumb are purely cosmetic — they read switch state from context to render the rail and knob. You can omit them entirely and render your own visual using the attrs slot prop on Switch.Root, or use renderless mode for full control over the rendered element.