27.5k

Radio

Migration guide for Radio from HeroUI v2 to v3

Refer to the v3 Radio documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.

Overview

The Radio component in HeroUI v3 has been redesigned with a compound component pattern, requiring explicit structure with Radio.Control, Radio.Indicator, and Radio.Content components.

Structure Changes

v2: Simple Structure

In v2, Radio used a simple structure with props:

import { RadioGroup, Radio } from "@heroui/react";

<RadioGroup label="Select city">
  <Radio value="london">London</Radio>
  <Radio value="tokyo" description="Capital of Japan">Tokyo</Radio>
</RadioGroup>

v3: Compound Components

In v3, Radio requires compound components:

import { RadioGroup, Radio, Label, Description } from "@heroui/react";

<RadioGroup>
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
      <Description>Capital of Japan</Description>
    </Radio.Content>
  </Radio>
</RadioGroup>

Key Changes

1. Component Structure

v2: Simple Radio with children as label
v3: Compound components: Radio.Control, Radio.Indicator, Radio.Content

2. Prop Changes

v2 Propv3 PropNotes
onValueChangeonChangeRenamed event handler
label (on RadioGroup)-Removed (use Label component)
description (on Radio)-Removed (use Description component)
size-Removed (use Tailwind CSS)
color-Removed (use Tailwind CSS)
classNames-Use className props
disableAnimation-Removed

3. Removed Props

The following props are no longer available in v3:

  • label (on RadioGroup) - Use Label component instead
  • description (on Radio) - Use Description component inside Radio.Content
  • size - Use Tailwind CSS classes
  • color - Use Tailwind CSS classes
  • classNames - Use className props on individual components
  • disableAnimation - Animations handled differently

Migration Examples

Basic Usage

import { RadioGroup, Radio } from "@heroui/react";

export default function App() {
  return (
    <RadioGroup label="Select your favorite city">
      <Radio value="buenos-aires">Buenos Aires</Radio>
      <Radio value="sydney">Sydney</Radio>
      <Radio value="san-francisco">San Francisco</Radio>
    </RadioGroup>
  );
}
import { RadioGroup, Radio, Label } from "@heroui/react";

export default function App() {
  return (
    <RadioGroup>
      <Label>Select your favorite city</Label>
      <Radio value="buenos-aires">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>Buenos Aires</Label>
        </Radio.Content>
      </Radio>
      <Radio value="sydney">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>Sydney</Label>
        </Radio.Content>
      </Radio>
      <Radio value="san-francisco">
        <Radio.Control>
          <Radio.Indicator />
        </Radio.Control>
        <Radio.Content>
          <Label>San Francisco</Label>
        </Radio.Content>
      </Radio>
    </RadioGroup>
  );
}

With Description

<RadioGroup label="Select city">
  <Radio value="london" description="Capital of England">
    London
  </Radio>
  <Radio value="tokyo" description="Capital of Japan">
    Tokyo
  </Radio>
</RadioGroup>
import { Description } from "@heroui/react";

<RadioGroup>
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
      <Description>Capital of England</Description>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
      <Description>Capital of Japan</Description>
    </Radio.Content>
  </Radio>
</RadioGroup>

Controlled

import { useState } from "react";

const [selected, setSelected] = useState("london");

<RadioGroup
  value={selected}
  onValueChange={setSelected}
>
  <Radio value="london">London</Radio>
  <Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
import { useState } from "react";

const [selected, setSelected] = useState("london");

<RadioGroup value={selected} onChange={setSelected}>
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
    </Radio.Content>
  </Radio>
</RadioGroup>

Horizontal Orientation

<RadioGroup orientation="horizontal" label="Select city">
  <Radio value="london">London</Radio>
  <Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
<RadioGroup orientation="horizontal">
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
    </Radio.Content>
  </Radio>
</RadioGroup>

With Validation

<RadioGroup
  isInvalid
  errorMessage="Please select an option"
  label="Select city"
>
  <Radio value="london">London</Radio>
  <Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
import { FieldError } from "@heroui/react";

<RadioGroup isInvalid>
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
    </Radio.Content>
  </Radio>
  <FieldError>Please select an option</FieldError>
</RadioGroup>

Disabled State

<RadioGroup isDisabled label="Select city">
  <Radio value="london">London</Radio>
  <Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
<RadioGroup isDisabled>
  <Label>Select city</Label>
  <Radio value="london">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
  <Radio value="tokyo">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Tokyo</Label>
    </Radio.Content>
  </Radio>
</RadioGroup>

Custom Styling

<RadioGroup
  classNames={{
    base: "custom-base",
    wrapper: "custom-wrapper"
  }}
>
  <Radio
    classNames={{
      base: "custom-radio-base",
      control: "custom-control"
    }}
    value="london"
  >
    London
  </Radio>
</RadioGroup>
<RadioGroup className="custom-base">
  <Radio className="custom-radio-base" value="london">
    <Radio.Control className="custom-control">
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>London</Label>
    </Radio.Content>
  </Radio>
</RadioGroup>

Component Anatomy

The v3 Radio follows this structure:

RadioGroup (Root)
  ├── Label (optional)
  ├── Radio
  │   ├── Radio.Control
  │   │   └── Radio.Indicator
  │   └── Radio.Content
  │       ├── Label
  │       └── Description (optional)
  └── FieldError (optional)

Breaking Changes Summary

  1. Component Structure: Must use compound components (Radio.Control, Radio.Indicator, Radio.Content)
  2. Label Handling: label prop removed - use Label component
  3. Description Handling: description prop removed - use Description component inside Radio.Content
  4. Event Handler: onValueChangeonChange
  5. Styling Props Removed: size, color - use Tailwind CSS
  6. ClassNames Removed: Use className props on individual components
  7. Error Message: Use FieldError component instead of errorMessage prop

Tips for Migration

  1. Update structure: Wrap Radio content in Radio.Control, Radio.Indicator, and Radio.Content
  2. Add Label: Use Label component for RadioGroup label
  3. Add Description: Use Description component inside Radio.Content
  4. Update event handler: Change onValueChange to onChange
  5. Add indicator: Include Radio.Indicator inside Radio.Control
  6. Update styling: Use Tailwind CSS classes for sizes and colors
  7. Add error: Use FieldError component for validation messages

Need Help?

For v3 RadioGroup features and API:

For community support: