Radio Group
Picks exactly one option from a small set, with every option visible at once.
<RadioGroup
defaultValue="daily"
aria-label="Scan frequency"
className="w-fit"
>
<Field orientation="horizontal">
<RadioGroupItem value="hourly" id="frequency-hourly" />
<FieldLabel htmlFor="frequency-hourly">Hourly</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="daily" id="frequency-daily" />
<FieldLabel htmlFor="frequency-daily">Daily</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="weekly" id="frequency-weekly" />
<FieldLabel htmlFor="frequency-weekly">Weekly</FieldLabel>
</Field>
</RadioGroup>Usage
import { Field, FieldLabel } from "@zenoxai/ui/components/field"
import { RadioGroup, RadioGroupItem } from "@zenoxai/ui/components/radio-group"
<RadioGroup defaultValue="daily" aria-label="Scan frequency">
<Field orientation="horizontal">
<RadioGroupItem value="hourly" id="frequency-hourly" />
<FieldLabel htmlFor="frequency-hourly">Hourly</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="daily" id="frequency-daily" />
<FieldLabel htmlFor="frequency-daily">Daily</FieldLabel>
</Field>
</RadioGroup>
Use a radio group for two to five options that the user should compare before choosing, and
when one option is always selected. Set defaultValue so the group never starts empty.
For more options, or when the choice is secondary, use a Select. For options that can be combined, use Checkboxes. For a choice that changes a view right away, such as a filter, a Toggle Group is more compact.
Lay out each option as a horizontal Field with a FieldLabel pointing at
the item’s id. The group is a vertical grid with an 8px gap; override it with className.
Examples
With a description
Put the group in a FieldSet with a FieldLegend that names the choice, and give each option
a FieldDescription in a FieldContent.
<FieldSet className="max-w-sm">
<FieldLegend variant="label">When an alert is resolved</FieldLegend>
<RadioGroup defaultValue="notify-owner">
<Field orientation="horizontal">
<RadioGroupItem value="notify-owner" id="resolve-owner" />
<FieldContent>
<FieldLabel htmlFor="resolve-owner">Notify the owner</FieldLabel>
<FieldDescription>
Only the assigned analyst gets an email.
</FieldDescription>
</FieldContent>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="notify-team" id="resolve-team" />
<FieldContent>
<FieldLabel htmlFor="resolve-team">Notify the team</FieldLabel>
<FieldDescription>
Everyone on the tenant's SOC team gets an email.
</FieldDescription>
</FieldContent>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="silent" id="resolve-silent" />
<FieldContent>
<FieldLabel htmlFor="resolve-silent">Do not notify</FieldLabel>
<FieldDescription>
The change appears in the alert history only.
</FieldDescription>
</FieldContent>
</Field>
</RadioGroup>
</FieldSet>Choice cards
Wrap each option’s Field in a FieldLabel to turn it into a bordered card. The whole card is
clickable, and the selected card is highlighted. Use FieldTitle for the option name inside
the card, since the card itself is the label.
<RadioGroup
defaultValue="external"
aria-label="Scan type"
className="max-w-sm"
>
<FieldLabel htmlFor="scan-external">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>External scan</FieldTitle>
<FieldDescription>
Internet-facing domains and IPs. About 10 minutes.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="external" id="scan-external" />
</Field>
</FieldLabel>
<FieldLabel htmlFor="scan-internal">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Internal scan</FieldTitle>
<FieldDescription>
Hosts behind the network agent. About 1 hour.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="internal" id="scan-internal" />
</Field>
</FieldLabel>
</RadioGroup>Disabled
disabled on a RadioGroupItem disables one option; on the RadioGroup it disables them all.
Set data-disabled on the option’s Field to dim its label. Say in the label why the option
is not available.
<RadioGroup defaultValue="30" aria-label="Log retention" className="w-fit">
<Field orientation="horizontal">
<RadioGroupItem value="30" id="retention-30" />
<FieldLabel htmlFor="retention-30">30 days</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="90" id="retention-90" />
<FieldLabel htmlFor="retention-90">90 days</FieldLabel>
</Field>
<Field orientation="horizontal" data-disabled>
<RadioGroupItem value="365" id="retention-365" disabled />
<FieldLabel htmlFor="retention-365">
1 year (Enterprise plan)
</FieldLabel>
</Field>
</RadioGroup>Controlled
Pass value and onValueChange. RadioGroup is not generic, so onValueChange receives
unknown; cast it to the type of your values.
Value: open
function RadioGroupControlled() {
const [view, setView] = React.useState("open")
return (
<div className="grid justify-items-center gap-3">
<RadioGroup
value={view}
onValueChange={(value) => setView(value as string)}
aria-label="Alerts to show"
className="flex w-fit gap-4"
>
<Field orientation="horizontal" className="w-auto">
<RadioGroupItem value="open" id="view-open" />
<FieldLabel htmlFor="view-open">Open</FieldLabel>
</Field>
<Field orientation="horizontal" className="w-auto">
<RadioGroupItem value="mine" id="view-mine" />
<FieldLabel htmlFor="view-mine">Assigned to me</FieldLabel>
</Field>
<Field orientation="horizontal" className="w-auto">
<RadioGroupItem value="all" id="view-all" />
<FieldLabel htmlFor="view-all">All</FieldLabel>
</Field>
</RadioGroup>
<p className="text-sm text-text-secondary">Value: {view}</p>
</div>
)
}Accessibility
- The group has
role="radiogroup"and needs a name:aria-label, oraria-labelledbypointing at a visible heading. AFieldLegendnames the surroundingFieldSet, not the group itself. - Tab moves focus into the group to the selected option and out again in one step. Arrow keys move between options and select them.
- Each item renders a
<span role="radio">with a hidden<input>beside it. Theidgoes to the hidden input, soFieldLabel htmlFornames the item and selects it on click. nameonRadioGroupsubmits the selected value with a native form.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
RadioGroup
RadioGroup picks exactly one option from a short list that stays in view, such as a plan or a frequency. For a long list, use Select; for an on/off choice, Checkbox or Switch; for a compact segmented control, ToggleGroup.
| Prop | Type | Default |
|---|---|---|
defaultValue | anyThe uncontrolled value of the radio button that should be initially selected. | - |
disabled | booleanWhether the component should ignore user interaction. | false |
form | stringIdentifies the form that owns the radio inputs. Useful when the radio group is rendered outside the form. | - |
inputRef | Ref<HTMLInputElement>A ref to access the hidden input element. | - |
name | stringIdentifies the field when a form is submitted. | - |
onValueChange | ((value: any, eventDetails: { reason: "none"; event: Event; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element; }) => void)Callback fired when the value changes. | - |
readOnly | booleanWhether the user should be unable to select a different radio button in the group. | false |
render | ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, RadioGroupState>Allows you to replace the component's HTML element with a different tag, or compose it with another component. | - |
required | booleanWhether the user must choose a value before submitting a form. | false |
value | anyThe controlled value of the radio item that should be currently selected. | - |
RadioGroupItem
| Prop | Type | Default |
|---|---|---|
disabled | booleanWhether the component should ignore user interaction. | - |
inputRef | Ref<HTMLInputElement>A ref to access the hidden input element. | - |
nativeButton | booleanWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). | true |
readOnly | booleanWhether the user should be unable to select the radio button. | - |
render | ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, RadioRootState>Allows you to replace the component's HTML element with a different tag, or compose it with another component. | - |
required | booleanWhether the user must choose a value before submitting a form. | - |
value* | anyThe unique identifying value of the radio in a group. | - |