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.
Structure Changes
In v2, Radio used a simple structure with props:
import { RadioGroup, Radio } from "@heroui/react";
export default function App() {
return (
<RadioGroup label="Select city">
<Radio value="london">London</Radio>
<Radio value="tokyo" description="Capital of Japan">Tokyo</Radio>
</RadioGroup>
);
}In v3, Radio requires compound components:
import { RadioGroup, Radio, Label, Description } from "@heroui/react";
export default function App() {
return (
<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 Prop | v3 Location | Notes |
|---|---|---|
onValueChange | onChange | Renamed event handler |
label (on RadioGroup) | — | Use Label component |
description (on Radio) | — | Use Description component inside Radio.Content |
size | — | Removed (use Tailwind CSS) |
color | — | Removed (use Tailwind CSS) |
classNames | — | Use className props on individual components |
disableAnimation | — | Removed (animations handled differently) |
| — | variant | New prop on RadioGroup: "primary" (default) or "secondary" for lower emphasis styling |
| — | isReadOnly | New prop on RadioGroup: prevents value changes while keeping the group focusable |
Migration Examples
Form Validation
{/* With description */}
<RadioGroup label="Select city">
<Radio value="london" description="Capital of England">
London
</Radio>
</RadioGroup>
{/* With validation */}
<RadioGroup
isInvalid
errorMessage="Please select an option"
label="Select city"
>
<Radio value="london">London</Radio>
</RadioGroup>import { Label, Description, FieldError } from "@heroui/react";
{/* With description */}
<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>
</RadioGroup>
{/* With validation */}
<RadioGroup isInvalid>
<Label>Select city</Label>
<Radio value="london">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label>London</Label>
</Radio.Content>
</Radio>
<FieldError>Please select an option</FieldError>
</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>Variants
v3 introduces a variant prop on RadioGroup with "primary" (default) and "secondary" options:
{/* Primary variant (default) */}
<RadioGroup variant="primary">
<Label>Select city</Label>
<Radio value="london">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label>London</Label>
</Radio.Content>
</Radio>
</RadioGroup>
{/* Secondary variant - lower emphasis, suitable for Surface components */}
<RadioGroup variant="secondary">
<Label>Select city</Label>
<Radio value="london">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label>London</Label>
</Radio.Content>
</Radio>
</RadioGroup>Read Only
v3 supports isReadOnly on RadioGroup, which prevents value changes while keeping the group focusable:
<RadioGroup isReadOnly defaultValue="london">
<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>Component Anatomy
The v3 Radio follows this structure:
RadioGroup (Root)
├── Label (optional)
├── Radio
│ ├── Radio.Control
│ │ └── Radio.Indicator
│ └── Radio.Content
│ ├── Label
│ └── Description (optional)
└── FieldError (optional)Summary
- Component Structure: Must use compound components (
Radio.Control,Radio.Indicator,Radio.Content) - Label Handling:
labelprop removed - useLabelcomponent - Description Handling:
descriptionprop removed - useDescriptioncomponent insideRadio.Content - Event Handler:
onValueChange→onChange - Styling Props Removed:
size,color- use Tailwind CSS - ClassNames Removed: Use
classNameprops on individual components - Error Message: Use
FieldErrorcomponent instead oferrorMessageprop - New
variantProp:RadioGroupsupports"primary"(default) and"secondary"for lower emphasis styling - New
isReadOnlyProp:RadioGroupsupportsisReadOnlyto prevent value changes while keeping the group focusable