<Radio.Group
name="playground-plan"
defaultValue="pro"
ariaLabel="Plan"
>
<Stack
direction="row"
gap={4}
>
<Radio.Item
value="starter"
>
Starter
</Radio.Item>
<Radio.Item
value="pro"
>
Pro
</Radio.Item>
<Radio.Item
value="team"
>
Team
</Radio.Item>
</Stack>
</Radio.Group>Features
- Groups options with a shared label and description.
- Supports controlled and uncontrolled selection.
- Shows helper text under each option.
- Extends the click area to a container with
stretched. - Supports responsive sizes, disabled and error states.
Radio.Group
Render each option as a Radio.Item with a unique value, and name the group with Radio.GroupLabel. Set defaultValue to choose the initial option. A selected radio can't be cleared by clicking it, so use a Checkbox for a single on/off choice.
import { Radio, Stack, Text } from "@vortexlabs/vortex";
<Radio.Group name="delivery" defaultValue="standard">
<Stack gap={4}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Delivery method</Text>
</Radio.GroupLabel>
<Stack gap={3}>
<Radio.Item value="standard">Standard delivery</Radio.Item>
<Radio.Item value="express">Express delivery</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Group Description
Use Radio.GroupDescription for text that applies to every option.
<Radio.Group name="billing" defaultValue="monthly">
<Stack gap={4}>
<Stack gap={1}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Billing interval</Text>
</Radio.GroupLabel>
<Radio.GroupDescription>
<Text size="body-sm-desktop" color="subtle">You can change this at any time.</Text>
</Radio.GroupDescription>
</Stack>
<Stack gap={3}>
<Radio.Item value="monthly">Monthly</Radio.Item>
<Radio.Item value="yearly">Yearly</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Sizes
Radio comes in sm and md; the default is md. Pass a breakpoint object to change size by screen width.
<Radio.Group name="size" defaultValue="small" ariaLabel="Radio sizes">
<Stack gap={4}>
<Radio.Item value="small" size="sm">Small</Radio.Item>
<Radio.Item value="medium" size="md">Medium</Radio.Item>
<Radio.Item value="responsive" size={{ xs: "sm", md: "md" }}>Responsive</Radio.Item>
</Stack>
</Radio.Group>Helper Text
Use children for the label and helperText for supporting information.
<Radio.Group name="access" defaultValue="invite">
<Stack gap={4}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Workspace access</Text>
</Radio.GroupLabel>
<Stack gap={3}>
<Radio.Item value="invite" helperText="Only people you invite can join.">Invite only</Radio.Item>
<Radio.Item value="domain" helperText="Anyone with a company email address can join.">Company domain</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Controlled Selection
Pass value to Radio.Group and update it in onChange. Use null to clear the selection.
"use client";
import { Button, Radio, Stack, Text } from "@vortexlabs/vortex";
import { useState } from "react";
export const RadioControlledExample = () => {
const [value, setValue] = useState<string | null>("monthly");
return (
<Stack gap={4}>
<Radio.Group
name="billing-controlled"
value={value}
onChange={({ value }) => setValue(value)}
>
<Stack gap={4}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Billing interval</Text>
</Radio.GroupLabel>
<Stack gap={3}>
<Radio.Item value="monthly">Monthly</Radio.Item>
<Radio.Item value="yearly">Yearly</Radio.Item>
</Stack>
</Stack>
</Radio.Group>
<Text size="body-sm-desktop">Selected: {value ?? "None"}</Text>
<Button variant="secondary" onClick={() => setValue(null)}>
Clear selection
</Button>
</Stack>
);
};Stretched Click Area
Set stretched to make the whole container clickable, such as a card. Place the item directly inside it; other links or buttons in the container need position: relative; z-index: 1.
<Radio.Group name="plan" defaultValue="team" ariaLabel="Plan">
<Stack direction="row" gap={3}>
<Stack padding={4} borderRadius="md" borderColor="default">
<Radio.Item stretched value="starter" helperText="Up to 3 projects">Starter</Radio.Item>
</Stack>
<Stack padding={4} borderRadius="md" borderColor="default">
<Radio.Item stretched value="team" helperText="Unlimited projects">Team</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Disabled Options
Set disabled on an item to make that option unavailable, or on Radio.Group to disable all options.
<Radio.Group name="export-format" defaultValue="csv">
<Stack gap={4}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Export format</Text>
</Radio.GroupLabel>
<Stack gap={3}>
<Radio.Item value="csv">CSV</Radio.Item>
<Radio.Item value="pdf" disabled helperText="PDF export is unavailable for this report.">PDF</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Error State
Set error on the group and explain the fix in Radio.GroupDescription. Pass native attributes like required through inputAttributes.
<Radio.Group name="region" error>
<Stack gap={4}>
<Stack gap={1}>
<Radio.GroupLabel>
<Text size="body-md-desktop" weight="medium">Data storage region</Text>
</Radio.GroupLabel>
<Radio.GroupDescription>
<Text size="body-sm-desktop" color="critical">Choose a region to continue.</Text>
</Radio.GroupDescription>
</Stack>
<Stack gap={3}>
<Radio.Item value="au" inputAttributes={{ required: true }}>Australia</Radio.Item>
<Radio.Item value="eu">Europe</Radio.Item>
</Stack>
</Stack>
</Radio.Group>Accessibility
ArrowDown or ArrowRight selects the next option, and ArrowUp or ArrowLeft the previous one. Selection wraps and skips disabled options.Space while a radio is focused selects it.Radio.GroupLabel or ariaLabel, and provide ariaLabel for items without visible text.