Skip to content

Radio

An easily stylable radio button component.

Best apple

Usage guidelines

  • Radio buttons must be grouped: Use RadioGroup to provide shared value state, keyboard navigation, and form behavior.
  • Form controls must have an accessible name: Label the radio group with aria-labelledby or FieldsetLegend, and label each radio with a native <label> or FieldLabel. See Labeling a radio group and the forms guide.

Anatomy

Import the radio parts and compose them with a group:

vue
<script setup lang="ts">
import { RadioGroup, RadioIndicator, RadioRoot } from 'base-ui-vue'
</script>

<template>
  <RadioGroup>
    <RadioRoot>
      <RadioIndicator />
    </RadioRoot>
  </RadioGroup>
</template>

Examples

Labeling a radio group

Label the group with aria-labelledby and a sibling label element:

vue
<div id="storage-type-label">
  Storage type
</div>

<RadioGroup aria-labelledby="storage-type-label">
  <!-- radio options -->
</RadioGroup>

An enclosing <label> is the simplest labeling pattern for each radio:

vue
<RadioGroup default-value="ssd">
  <label>
    <RadioRoot value="ssd" />
    SSD
  </label>
</RadioGroup>

Rendering as a native button

By default, RadioRoot renders a <span> element to support enclosing labels. Prefer rendering each radio as a native button when using sibling labels (for/id).

vue
<div id="storage-type">
  Storage type
</div>

<RadioGroup default-value="ssd" aria-labelledby="storage-type">
  <div>
    <label for="storage-type-ssd">SSD</label>
    <RadioRoot
      value="ssd"
      id="storage-type-ssd"
      as="button"
      :native-button="true"
    >
      <RadioIndicator />
    </RadioRoot>
  </div>
</RadioGroup>

Native buttons with wrapping labels are supported by using renderless mode so the hidden input is placed outside the label:

vue
<script setup lang="ts">
import { RadioGroup, RadioIndicator, RadioRoot, Slot } from 'base-ui-vue'
</script>

<template>
  <RadioGroup default-value="ssd">
    <RadioRoot value="ssd" :as="Slot" :native-button="true" v-slot="{ props, ref }">
      <label>
        <button :ref="ref" v-bind="props">
          <RadioIndicator />
        </button>
        SSD
      </label>
    </RadioRoot>
  </RadioGroup>
</template>

Form integration

Use Field and Fieldset for group labeling and form integration:

vue
<script setup lang="ts">
import {
  FieldItem,
  FieldLabel,
  FieldRoot,
  FieldsetLegend,
  FieldsetRoot,
  Form,
  RadioGroup,
  RadioRoot,
} from 'base-ui-vue'
</script>

<template>
  <Form>
    <FieldRoot name="storageType">
      <FieldsetRoot :as="RadioGroup" default-value="ssd">
        <FieldsetLegend>Storage type</FieldsetLegend>
        <FieldItem>
          <FieldLabel>
            <RadioRoot value="ssd" />
            SSD
          </FieldLabel>
        </FieldItem>
        <FieldItem>
          <FieldLabel>
            <RadioRoot value="hdd" />
            HDD
          </FieldLabel>
        </FieldItem>
      </FieldsetRoot>
    </FieldRoot>
  </Form>
</template>

API reference

Group

Provides a shared state to a series of radio buttons. Renders a <div> element.

PropTypeDefaultDescription
asstring | Component'div'The element or component used for the radio group.
valueValueundefinedThe controlled selected radio value. To render an uncontrolled group, use default-value instead.
default-valueValueundefinedThe initially selected radio value. To render a controlled group, use value instead.
disabledbooleanfalseWhether the group should ignore user interaction.
read-onlybooleanfalseWhether the user should be unable to select a different radio.
requiredbooleanfalseWhether the user must choose a value before submitting a form.
namestringundefinedIdentifies the field when a form is submitted.
formstringundefinedIdentifies the form that owns the radio inputs. Useful when the group is rendered outside the form.
input-refanyundefinedA ref or callback to access the currently selected hidden input element.
classany | ((state: State) => any)undefinedCSS class applied to the element, or a function that returns a class based on the component's state.
styleStyleValue | ((state: State) => StyleValue)undefinedStyle applied to the element, or a function that returns a style object based on the component's state.
EmitsTypeDescription
value-change(value: Value, details: EventDetails) => voidEmitted when the selected radio value changes.
AttributeDescription
data-disabledPresent when the radio group is disabled.
data-readonlyPresent when the radio group is read-only.
data-requiredPresent when the radio group is required.
data-validPresent when the radio group is valid.
data-invalidPresent when the radio group is invalid.
data-dirtyPresent when the radio group's value has changed.
data-touchedPresent when the radio group has been touched.
data-filledPresent when a radio value is selected.
data-focusedPresent when focus is inside the radio group.

Root

Represents the radio button itself. Renders a <span> element and a hidden <input> beside.

PropTypeDefaultDescription
asstring | Component'span'The element or component used for the radio root.
valueValue-The unique identifying value of the radio in a group.
disabledbooleanfalseWhether the component should ignore user interaction.
read-onlybooleanfalseWhether the user should be unable to select the radio button.
requiredbooleanfalseWhether the user must choose a value before submitting a form.
input-refanyundefinedA ref or callback to access the hidden <input> element.
native-buttonbooleanfalseWhether the component renders a native <button> element when replacing it via the as prop. Set to true if the rendered element is a native button.
classany | ((state: State) => any)undefinedCSS class applied to the element, or a function that returns a class based on the component's state.
styleStyleValue | ((state: State) => StyleValue)undefinedStyle applied to the element, or a function that returns a style object based on the component's state.
AttributeDescription
data-checkedPresent when the radio is checked.
data-uncheckedPresent when the radio is unchecked.
data-disabledPresent when the radio is disabled.
data-readonlyPresent when the radio is read-only.
data-requiredPresent when the radio is required.
data-validPresent when the radio is valid.
data-invalidPresent when the radio is invalid.
data-dirtyPresent when the radio's value has changed.
data-touchedPresent when the radio has been touched.
data-filledPresent when the radio is checked.
data-focusedPresent when the radio is focused.

Indicator

Indicates whether the radio button is selected. Renders a <span> element.

PropTypeDefaultDescription
asstring | Component'span'The element or component used for the indicator.
keep-mountedbooleanfalseWhether to keep the element in the DOM when the radio button is inactive.
classany | ((state: State) => any)undefinedCSS class applied to the element, or a function that returns a class based on the component's state.
styleStyleValue | ((state: State) => StyleValue)undefinedStyle applied to the element, or a function that returns a style object based on the component's state.
AttributeDescription
data-checkedPresent when the radio is checked.
data-uncheckedPresent when the radio is unchecked.
data-disabledPresent when the radio is disabled.
data-readonlyPresent when the radio is read-only.
data-requiredPresent when the radio is required.
data-validPresent when the radio is valid.
data-invalidPresent when the radio is invalid.
data-dirtyPresent when the radio's value has changed.
data-touchedPresent when the radio has been touched.
data-filledPresent when the radio is checked.
data-focusedPresent when the radio is focused.
data-starting-stylePresent when the indicator is animating in.
data-ending-stylePresent when the indicator is animating out.