Lets the user pick exactly one option from a small, visible set. Use with Radio children.
import { Radio, RadioGroup } from "@rdloom/react";
export default function RadioGroupBasicExample() {
return (
<RadioGroup label="Plan" defaultValue="pro">
<Radio value="free">Free</Radio>
<Radio value="pro">Pro</Radio>
<Radio value="team">Team</Radio>
</RadioGroup>
);
}Installation
npx rdloom add radio-groupCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/radio-group.jsonWorks, but without upgrade tracking.
Usage
import { Radio, RadioGroup } from "@rdloom/react";
<RadioGroup label="Plan" defaultValue="pro">
<Radio value="free">Free</Radio>
<Radio value="pro">Pro</Radio>
<Radio value="team">Team</Radio>
</RadioGroup>Horizontal
import { Radio, RadioGroup } from "@rdloom/react";
export default function RadioGroupHorizontalExample() {
return (
<RadioGroup label="Billing" orientation="horizontal" defaultValue="monthly">
<Radio value="monthly">Monthly</Radio>
<Radio value="yearly">Yearly</Radio>
</RadioGroup>
);
}Invalid
import { Button, Radio, RadioGroup } from "@rdloom/react";
export default function RadioGroupInvalidExample() {
return (
<form className="flex flex-col items-start gap-3" onSubmit={(e) => e.preventDefault()}>
{/* Submit without choosing to see the error. */}
<RadioGroup label="Shipping" isRequired>
<Radio value="standard">Standard</Radio>
<Radio value="express">Express</Radio>
</RadioGroup>
<Button type="submit">Continue</Button>
</form>
);
}Disabled
import { Radio, RadioGroup } from "@rdloom/react";
export default function RadioGroupDisabledExample() {
return (
<RadioGroup label="Region" defaultValue="eu" isDisabled>
<Radio value="eu">Europe</Radio>
<Radio value="us">United States</Radio>
</RadioGroup>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
labelrequiredVisible group label. | string | none |
descriptionHelp text shown under the options. | string | none |
errorMessageShown when the group is invalid. | string | none |
orientationLayout direction of the options. | "vertical" | "horizontal" | "vertical" |
valueControlled selected value. | string | none |
defaultValueInitial value when uncontrolled. | string | none |
isDisabledDisables every option. | boolean | false |
isInvalidMarks the group as invalid and shows errorMessage. | boolean | false |
isRequiredRequires a selection for form submission. | boolean | false |
childrenrequiredRadio options. | node | none |
onChangeCalled with the newly selected value. | (value: string) => void | none |
Accessibility
Role radiogroup, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Arrow keys move and select
- Tab enters and leaves the group
Screen readers announce
- Entering the group announces the group label
- Each option: radio button, its label, checked state and position (2 of 3)
- Arrow keys announce the newly selected option
What your code must do
- Group has a visible label
- Only the selected radio is in the tab order
Guidelines
Use it when
- 2 to 6 mutually exclusive options that should all be visible
Avoid it when
- Many options: use Select
- Independent options: use Checkbox
Don't
- A single radio on its own
- No option selected when a sensible default exists
- Passing isInvalid for required or format checks (even isInvalid={false}): any defined value takes over validity and hides the built-in errors. Use isRequired and validate; pass isInvalid only for errors the app finds itself, such as from the server
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-action-primary--rd-color-border-strong--rd-color-surface-default--rd-color-text-default--rd-color-text-muted--rd-color-feedback-danger--rd-color-focus-ring