Radio
A headless radio button component for single-selection groups with keyboard navigation and roving tabindex.
Usage
Radio buttons must be used within a Radio.Group. Use v-model on the group to bind the selected value:
Selected: none
Anatomy
<script setup lang="ts">
import { Radio } from '@vuetify/v0'
</script>
<template>
<Radio.Group>
<Radio.Root>
<Radio.Indicator />
</Radio.Root>
<Radio.Root>
<Radio.Indicator />
</Radio.Root>
</Radio.Group>
<!-- With form submission -->
<Radio.Group>
<Radio.Root>
<Radio.Indicator />
<Radio.HiddenInput />
</Radio.Root>
<Radio.Root>
<Radio.Indicator />
<Radio.HiddenInput />
</Radio.Root>
</Radio.Group>
</template>Auto-Select First Option
Radio groups are inherently mandatory—once a selection is made, it can only be changed, not cleared. Use mandatory="force" to automatically select the first non-disabled option on mount:
Selected plan:
Accessibility
The Radio components handle all ARIA attributes automatically:
role="radiogroup"on the Grouprole="radio"on each Rootaria-checkedreflects checked statearia-disabledwhen radio is disabledaria-requiredfor form validation (set on Group)aria-labelfrom thelabelprop- Roving
tabindex- only the selected radio (or first if none) is tabbable - Space key selects the focused radio
- Arrow keys navigate between radios
For custom implementations, use renderless mode and bind the attrs slot prop to your element:
<template>
<Radio.Root v-slot="{ attrs }" renderless>
<div v-bind="attrs">
<!-- Custom radio visual -->
</div>
</Radio.Root>
</template>Keyboard Navigation
Arrow keys provide circular navigation within a radio group:
| Key | Action |
|---|---|
Space | Select focused radio |
ArrowUp / ArrowLeft | Move to previous radio |
ArrowDown / ArrowRight | Move to next radio |
Navigation automatically skips disabled items and wraps around.
Form Integration
Set the name prop on Radio.Group to enable form submission for all radios in the group:
<template>
<Radio.Group v-model="selected" name="size">
<Radio.Root value="small">
<Radio.Indicator />
Small
</Radio.Root>
<Radio.Root value="large">
<Radio.Indicator />
Large
</Radio.Root>
</Radio.Group>
</template>Each Radio.Root automatically renders a hidden native radio input with the shared name and its own value.
For custom form integration, use Radio.HiddenInput explicitly:
<template>
<Radio.Group>
<Radio.Root value="a">
<Radio.Indicator />
<Radio.HiddenInput name="custom" value="override" />
</Radio.Root>
</Radio.Group>
</template>Radio.Root
Props
namespace
stringNamespace for context provision to children (Indicator, HiddenInput)
Default: "v0:radio:root"
Slots
Radio.Group
Props
mandatory
boolean | "force"Auto-selects the first non-disabled item on mount. Radio groups are inherently mandatory (selection can only be changed, not cleared), so `mandatory="force"` is the only meaningful option.
Default: false
Events
update:model-value
[value: T]Slots
Radio.HiddenInput
Props
value
stringSubmitted value when checked (defaults to context value or 'on'). Use to override the Radio.Root value for form submission.
