apps/docs/content/docs/react/migration/(components)/radio.mdx
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>
);
}
v2: Simple Radio with children as label
v3: Compound components: Radio.Control, Radio.Indicator, Radio.Content
| 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 |
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <RadioGroup label="Select city"> <Radio value="london" description="Capital of England"> London </Radio> </RadioGroup> <RadioGroup isInvalid errorMessage="Please select an option" label="Select city" > <Radio value="london">London</Radio> </RadioGroup>
</Tab>
<Tab value="v3">
tsx import { Label, Description, FieldError } 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> </RadioGroup> <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>
</Tab>
</Tabs>
<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx 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>
```
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>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <RadioGroup orientation="horizontal" label="Select city"> <Radio value="london">London</Radio> <Radio value="tokyo">Tokyo</Radio> </RadioGroup>
</Tab>
<Tab value="v3">
tsx <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>
</Tab>
</Tabs>
v3 introduces a variant prop on RadioGroup with "primary" (default) and "secondary" options:
<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>
<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>
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>
The v3 Radio follows this structure:
RadioGroup (Root)
├── Label (optional)
├── Radio
│ ├── Radio.Control
│ │ └── Radio.Indicator
│ └── Radio.Content
│ ├── Label
│ └── Description (optional)
└── FieldError (optional)
Radio.Control, Radio.Indicator, Radio.Content)label prop removed - use Label componentdescription prop removed - use Description component inside Radio.ContentonValueChange → onChangesize, color - use Tailwind CSSclassName props on individual componentsFieldError component instead of errorMessage propvariant Prop: RadioGroup supports "primary" (default) and "secondary" for lower emphasis stylingisReadOnly Prop: RadioGroup supports isReadOnly to prevent value changes while keeping the group focusable