Radio Group

A set of checkable buttons, known as radio buttons, where no more than one of the buttons can be checked at a time.

<script setup lang="ts">
import { Label } from '@/components/ui/label'
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
</script>

<template>
  <RadioGroup default-value="comfortable">
    <div class="flex items-center space-x-2">
      <RadioGroupItem id="r1" value="default" />
      <Label for="r1">Default</Label>
    </div>
    <div class="flex items-center space-x-2">
      <RadioGroupItem id="r2" value="comfortable" />
      <Label for="r2">Comfortable</Label>
    </div>
    <div class="flex items-center space-x-2">
      <RadioGroupItem id="r3" value="compact" />
      <Label for="r3">Compact</Label>
    </div>
  </RadioGroup>
</template>

Installation

Install the packages

npm install @animate-ui/vue motion-v
pnpm add @animate-ui/vue motion-v
yarn add @animate-ui/vue motion-v
bun add @animate-ui/vue motion-v

Add the shadcn-vue component

npx shadcn-vue@latest add radio-group
pnpm dlx shadcn-vue@latest add radio-group
yarn dlx shadcn-vue@latest add radio-group
bun x shadcn-vue@latest add radio-group

Animate it

The CLI finds your shadcn-vue components through components.json, swaps their primitive imports for Animate UI's and removes the CSS animation classes Motion replaces.

npx @animate-ui/cli@latest animate radio-group
pnpm dlx @animate-ui/cli@latest animate radio-group
yarn dlx @animate-ui/cli@latest animate radio-group
bun x @animate-ui/cli@latest animate radio-group

Usage

<script setup lang="ts">
import {
  RadioGroupIndicator,
  RadioGroupItem,
  RadioGroupRoot,
} from '@animate-ui/vue/primitives/reka-ui';
</script>

<template>
  <RadioGroupRoot default-value="comfortable" aria-label="Density">
    <RadioGroupItem id="r1" value="default">
      <RadioGroupIndicator>
        <span class="size-2 rounded-full bg-current" />
      </RadioGroupIndicator>
    </RadioGroupItem>
    <label for="r1">Default</label>
  </RadioGroupRoot>
</template>

Animation

The motion of Animate UI's React radio group:

  • Indicator: the dot pops in when its item is selected. Its scale and its opacity spring from 0 to 1 (stiffness 200, damping 16: it overshoots a little before settling), and back to 0 the same way when another item is selected, then the indicator unmounts, as in reka-ui. The indicator element itself never moves: its content (the dot) animates, so shadcn-vue's centered dot stays centered.
  • Item scales to 0.97 while pressed (no hover scale), on Motion's default spring for scale (stiffness 550, damping 30).
  • In the demo, an item's fill is a layer of its own (before: in its classes) that grows from 70% while it fades in, in 300ms, and shrinks back as it fades out, like the Checkbox's: the dot pops in over it. The layer covers the border (before:-inset-px) and the border keeps its color. It's CSS, so copy the classes for the same effect; under reduced motion the layer only fades.
  • An item already selected when the group appears (the page loading, a dialog opening) shows its dot at rest: only a change of selection animates a dot.
  • Selecting with the arrow keys animates like a click.
  • Selecting again mid-animation turns back from where the dot is.
  • Under reduced motion, the dot only fades and nothing scales.
  • With force-mount, an unselected item's indicator stays in the DOM with its dot hidden.

API Reference

Every part takes exactly the props of reka-ui's Radio Group. Animate UI adds the animation props below. With as-child, a part renders your element with reka-ui's behaviour, without the animation.

RadioGroupRoot

reka-ui props only: nothing animates on the group itself.

RadioGroupItem

reka-ui props, plus:

PropTypeDefault
transition?
Transition{ type: 'spring', stiffness: 550, damping: 30, restSpeed: 10 }

RadioGroupIndicator

reka-ui props, plus:

PropTypeDefault
transition?
Transition{ type: 'spring', stiffness: 200, damping: 16 }
exit-transition?
Transitionthe same spring as transition

AnimateUIProvider's tempo scales these transitions with everything else.

Built by Skyleen. The source code is available on GitHub.

Last updated: 10/23/2026