Skip to main content

Radio

Radio is a form control for choosing a single option from a set, like a delivery method or billing interval. Each option has a label and optional helper text, and people click or tap an option to select it.

Import

import { Radio } from '@vortexlabs/vortex';
import type { RadioProps } from '@vortexlabs/vortex';

Other links

<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.

Delivery method
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.

Billing interval
You can change this at any time.
<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.

Workspace access
Only people you invite can join.
Anyone with a company email address can join.
<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.

Billing interval
Selected: monthly
"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.

Up to 3 projects
Unlimited projects
<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.

Export format
PDF export is unavailable for this report.
<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.

Data storage region
Choose a region to continue.
<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

Key
Description
Up arrowDown arrowLeft arrowRight arrow
ArrowDown or ArrowRight selects the next option, and ArrowUp or ArrowLeft the previous one. Selection wraps and skips disabled options.
Space
Pressing Space while a radio is focused selects it.
Name each group with Radio.GroupLabel or ariaLabel, and provide ariaLabel for items without visible text.