Components
A set of checkable buttons — known as radio buttons — where no more than one of the buttons can be checked at a time.
Playground
Field with a FieldLabel. The hit area extends invisibly past the 16px circle, so the target stays comfortable on touch screens.import {
RadioGroup,
RadioGroupItem,
} from "@workspace/ui/components/radio-group"
import { Field, FieldLabel } from "@workspace/ui/components/field"
<RadioGroup defaultValue="comfortable">
<Field orientation="horizontal">
<RadioGroupItem value="default" id="density-default" />
<FieldLabel htmlFor="density-default">Default</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="comfortable" id="density-comfortable" />
<FieldLabel htmlFor="density-comfortable">Comfortable</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="compact" id="density-compact" />
<FieldLabel htmlFor="density-compact">Compact</FieldLabel>
</Field>
</RadioGroup>FieldContent and add a FieldDescription for helper text — the radio stays aligned with the first line of the label.Get notified for every message in every channel.
Only get notified when someone mentions you directly.
<RadioGroup defaultValue="mentions">
<Field orientation="horizontal">
<RadioGroupItem value="all" id="notify-all" />
<FieldContent>
<FieldLabel htmlFor="notify-all">All new messages</FieldLabel>
<FieldDescription>
Get notified for every message in every channel.
</FieldDescription>
</FieldContent>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="mentions" id="notify-mentions" />
<FieldContent>
<FieldLabel htmlFor="notify-mentions">Mentions only</FieldLabel>
<FieldDescription>
Only get notified when someone mentions you directly.
</FieldDescription>
</FieldContent>
</Field>
</RadioGroup>Field in a FieldLabel to turn each option into a clickable card — the checked card picks up a primary border and background tint automatically.<RadioGroup defaultValue="pro">
<FieldLabel htmlFor="plan-starter">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Starter</FieldTitle>
<FieldDescription>
For personal projects and experiments.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="starter" id="plan-starter" />
</Field>
</FieldLabel>
<FieldLabel htmlFor="plan-pro">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Pro</FieldTitle>
<FieldDescription>
For small teams shipping to production.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="pro" id="plan-pro" />
</Field>
</FieldLabel>
</RadioGroup>FieldSet with a FieldLegend so assistive technology announces the question with each option. Set variant="label" on the legend so it renders at label size.<FieldSet>
<FieldLegend variant="label">Where should we ship your order?</FieldLegend>
<FieldDescription>
Delivery speed depends on the destination.
</FieldDescription>
<RadioGroup defaultValue="home">
<Field orientation="horizontal">
<RadioGroupItem value="home" id="ship-home" />
<FieldLabel htmlFor="ship-home" className="font-normal">
Home address
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="office" id="ship-office" />
<FieldLabel htmlFor="ship-office" className="font-normal">
Office address
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="pickup" id="ship-pickup" />
<FieldLabel htmlFor="ship-pickup" className="font-normal">
Pickup point
</FieldLabel>
</Field>
</RadioGroup>
</FieldSet>defaultValue for uncontrolled groups, or value and onValueChange to control the selection — the callback receives the newly selected item's value string.Notifying about: Direct messages and mentions
const [value, setValue] = React.useState("mentions")
<RadioGroup value={value} onValueChange={setValue}>
<Field orientation="horizontal">
<RadioGroupItem value="all" id="notify-all" />
<FieldLabel htmlFor="notify-all">All new messages</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="mentions" id="notify-mentions" />
<FieldLabel htmlFor="notify-mentions">
Direct messages and mentions
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="none" id="notify-none" />
<FieldLabel htmlFor="notify-none">Nothing</FieldLabel>
</Field>
</RadioGroup>disabled on the RadioGroup to disable every option, or on a single RadioGroupItem to disable just that option. Add data-disabled to the Field so the label dims with the circle.<RadioGroup defaultValue="standard">
<Field orientation="horizontal">
<RadioGroupItem value="standard" id="tier-standard" />
<FieldLabel htmlFor="tier-standard">Standard delivery</FieldLabel>
</Field>
<Field orientation="horizontal" data-disabled>
<RadioGroupItem value="express" id="tier-express" disabled />
<FieldLabel htmlFor="tier-express">
Express delivery (unavailable)
</FieldLabel>
</Field>
</RadioGroup>aria-invalid on each RadioGroupItem and data-invalid on the field wrapper to show the invalid styles — a destructive border and ring on the circle, and destructive text on the label. Once an option is checked, its border returns to primary.<RadioGroup>
<Field orientation="horizontal" data-invalid>
<RadioGroupItem value="yes" id="consent-yes" aria-invalid />
<FieldLabel htmlFor="consent-yes">Yes, I agree</FieldLabel>
</Field>
<Field orientation="horizontal" data-invalid>
<RadioGroupItem value="no" id="consent-no" aria-invalid />
<FieldLabel htmlFor="consent-no">No, I disagree</FieldLabel>
</Field>
</RadioGroup>dir="rtl" to the RadioGroup as well as the layout wrapper — Radix stamps its own direction on the group (defaulting to LTR), and the prop keeps the indicator centered and reverses arrow-key navigation. Alternatively, wrap the app in the design system's DirectionProvider.<FieldGroup dir="rtl">
<RadioGroup dir="rtl" defaultValue="monthly">
<Field orientation="horizontal">
<RadioGroupItem value="monthly" id="billing-monthly" />
<FieldLabel htmlFor="billing-monthly">فوترة شهرية</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="yearly" id="billing-yearly" />
<FieldLabel htmlFor="billing-yearly">فوترة سنوية</FieldLabel>
</Field>
</RadioGroup>
</FieldGroup>defaultValue or controlled via value + onValueChange. Inside a form the group submits the checked item's value under name like a native radio set. Arrow keys move focus and selection between items.| Component | Prop | Default |
|---|---|---|
| RadioGroup | value?: string | — |
| RadioGroup | defaultValue?: string | — |
| RadioGroup | onValueChange?: (value: string) => void | — |
| RadioGroup | disabled?: boolean | false |
| RadioGroup | required?: boolean | false |
| RadioGroup | name?: string | — |
| RadioGroup | orientation?: "horizontal" | "vertical" | — |
| RadioGroup | loop?: boolean | true |
| RadioGroupItem | value: string | required |
| RadioGroupItem | disabled?: boolean | false |
Tokens used
6 design tokens consumed by the Radio Group component.
--primary
Primary
--primary-foreground
Primary Foreground
--input
Input
--ring
Ring
--destructive
Destructive
--spacing
Spacing unit (4px)