Skip to content

Radio

A control that allows the user to select one option from a set. Radio items are usually rendered inside a Radio.Group.

Source Code

Areia's Radio uses DOM primitives: native radio inputs, labels, fieldsets, and legends.

Notification preference
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Notification preference"
    name="notification-basic"
    value="email"
  >
    <Radio.Item
      label="Email"
      value="email"
      name="notification-basic"
      checked
    />
    <Radio.Item
      label="SMS"
      value="sms"
      name="notification-basic"
    />
    <Radio.Item
      label="Push"
      value="push"
      name="notification-basic"
    />
  </Radio.Group>
));

Import

import { Radio } from "areia";

Usage

Contact method
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Contact method"
    name="contact"
    value="email"
  >
    <Radio.Item
      label="Email"
      value="email"
      name="contact"
      checked
    />
    <Radio.Item label="Phone" value="phone" name="contact" />
  </Radio.Group>
));

Examples

Default Vertical

Radio groups display vertically by default. Each radio has a label displayed to its right.

Account type
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Account type"
    name="account-type"
    value="personal"
  >
    <Radio.Item
      label="Personal"
      value="personal"
      name="account-type"
      checked
    />
    <Radio.Item label="Team" value="team" name="account-type" />
    <Radio.Item
      label="Enterprise"
      value="enterprise"
      name="account-type"
    />
  </Radio.Group>
));

Horizontal

Use orientation: "horizontal" for inline layouts. Items wrap when there is not enough space.

Size
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Size"
    name="size"
    orientation="horizontal"
    value="md"
  >
    <Radio.Item label="Small" value="sm" name="size" />
    <Radio.Item label="Medium" value="md" name="size" checked />
    <Radio.Item label="Large" value="lg" name="size" />
  </Radio.Group>
));

With Description

Add helper text below the radio items using the description prop.

Build mode

Choose how Areia should generate your output.

import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Build mode"
    name="build-mode"
    description="Choose how Areia should generate your output."
    value="standard"
  >
    <Radio.Item
      label="Standard"
      value="standard"
      name="build-mode"
      checked
    />
    <Radio.Item
      label="Optimized"
      value="optimized"
      name="build-mode"
    />
  </Radio.Group>
));

Control Position

Use controlPosition: "end" to place labels before radio buttons.

Options
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Options"
    name="control-position"
    controlPosition="end"
    value="a"
  >
    <Radio.Item
      label="Option A"
      value="a"
      name="control-position"
      checked
      controlPosition="end"
    />
    <Radio.Item
      label="Option B"
      value="b"
      name="control-position"
      controlPosition="end"
    />
  </Radio.Group>
));

Radio Card

Use appearance: "card" on the group and items to display each option as a selectable card. Combine it with the description prop on each item for richer content.

Plan
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Plan"
    name="plan-card"
    appearance="card"
    value="free"
  >
    <Radio.Item
      label="Free"
      description="For personal or hobby projects."
      value="free"
      name="plan-card"
      appearance="card"
      checked
    />
    <Radio.Item
      label="Pro"
      description="For professional websites and applications."
      value="pro"
      name="plan-card"
      appearance="card"
    />
    <Radio.Item
      label="Team"
      description="For teams that collaborate on multiple projects."
      value="team"
      name="plan-card"
      appearance="card"
    />
  </Radio.Group>
));

Radio Card Control on the Left

Use controlPosition: "start" on card radio items to place the radio control on the left of the label and description.

Plan
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Plan"
    name="plan-card-start"
    appearance="card"
    controlPosition="start"
    value="free"
  >
    <Radio.Item
      label="Free"
      description="For personal or hobby projects."
      value="free"
      name="plan-card-start"
      appearance="card"
      controlPosition="start"
      checked
    />
    <Radio.Item
      label="Pro"
      description="For professional websites."
      value="pro"
      name="plan-card-start"
      appearance="card"
      controlPosition="start"
    />
  </Radio.Group>
));

Rich Label Content

The label prop on Radio.Item accepts Ilha markup, so you can embed badges or other markup alongside the text.

Plan
import ilha from "ilha";
import { Badge, Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Plan"
    name="rich-plan"
    appearance="card"
    value="pro"
  >
    <Radio.Item
      label={
        <span class="flex items-center gap-2">
          Free
          <Badge variant="secondary">$0</Badge>
        </span>
      }
      description="For personal or hobby projects."
      value="free"
      name="rich-plan"
      appearance="card"
    />
    <Radio.Item
      label={
        <span class="flex items-center gap-2">
          Pro
          <Badge variant="success">Popular</Badge>
        </span>
      }
      description="For professional websites."
      value="pro"
      name="rich-plan"
      appearance="card"
      checked
    />
  </Radio.Group>
));

Radio Card Horizontal

Combine appearance: "card" with orientation: "horizontal" for a side-by-side card layout.

Plan
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Plan"
    name="plan-horizontal"
    orientation="horizontal"
    appearance="card"
    value="free"
  >
    <Radio.Item
      label="Free"
      value="free"
      name="plan-horizontal"
      appearance="card"
      checked
    />
    <Radio.Item
      label="Pro"
      value="pro"
      name="plan-horizontal"
      appearance="card"
    />
    <Radio.Item
      label="Team"
      value="team"
      name="plan-horizontal"
      appearance="card"
    />
  </Radio.Group>
));

With Error

Show validation errors at the group level using the error prop.

Payment method

Please select a payment method.

import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group
    legend="Payment method"
    name="payment"
    error="Please select a payment method."
  >
    <Radio.Item
      label="Card"
      value="card"
      name="payment"
      variant="error"
    />
    <Radio.Item
      label="Bank transfer"
      value="bank"
      name="payment"
      variant="error"
    />
  </Radio.Group>
));

Disabled

Disable the entire group or individual items.

Disabled group
Disabled item
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-6">
    <Radio.Group
      legend="Disabled group"
      name="disabled-group"
      disabled
      value="email"
    >
      <Radio.Item
        label="Email"
        value="email"
        name="disabled-group"
        checked
        disabled
      />
      <Radio.Item
        label="SMS"
        value="sms"
        name="disabled-group"
        disabled
      />
    </Radio.Group>
    <Radio.Group
      legend="Disabled item"
      name="disabled-item"
      value="email"
    >
      <Radio.Item
        label="Email"
        value="email"
        name="disabled-item"
        checked
      />
      <Radio.Item
        label="SMS"
        value="sms"
        name="disabled-item"
        disabled
      />
    </Radio.Group>
  </div>
));

Visually Hidden Legend

Use Radio.Legend with class: "sr-only" to keep the legend accessible to screen readers while hiding it visually.

Paths

Paths
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <p class="text-base font-medium text-areia-default">
      Paths
    </p>
    <Radio.Group>
      <Radio.Legend label="Paths" class="sr-only" />
      <Radio.Item
        label="Allow all paths"
        value="all"
        name="paths"
        checked
      />
      <Radio.Item
        label="Specific paths"
        value="specific"
        name="paths"
      />
    </Radio.Group>
  </div>
));

Custom Legend Styling

Use Radio.Legend when you need custom typography, colors, or layout instead of the legend string prop.

Notification preference
import ilha from "ilha";
import { Radio } from "areia";

export default ilha.render(() => (
  <Radio.Group>
    <Radio.Legend
      label="Notification preference"
      class="text-sm uppercase tracking-wide text-areia-subtle"
    />
    <Radio.Item
      label="Email"
      value="email"
      name="custom-legend"
      checked
    />
    <Radio.Item label="SMS" value="sms" name="custom-legend" />
  </Radio.Group>
));

API Reference

Radio.Group

Container for radio buttons with legend, description, and error support.

PropTypeDefaultDescription
legendunknown-Legend content for the group.
first argumentunknown[]-Radio item markup when no group props are needed.
second argumentunknown[]-Radio item markup, usually Radio.Item(...) calls.
orientation"vertical" | "horizontal""vertical"Layout direction of the radio items.
appearance"default" | "card""default"Visual appearance used for group layout. Pass the same value to items for card styling.
errorunknown-Error message for the group.
descriptionunknown-Helper text for the group.
disabledboolean-Whether all controls in the fieldset are disabled.
controlPosition"start" | "end"-Position of the radio control relative to the label.
namestring-Native form submission name for grouped radio items.
classstring-Additional CSS classes.
classNamestring-Alias for class.

Radio.Legend

Composable legend sub-component for Radio.Group. Use it instead of the legend prop when you need custom legend styling.

PropTypeDefaultDescription
labelunknown-Legend content.
classstring-Additional CSS classes.
classNamestring-Alias for class.

Radio.Item

Individual radio button within Radio.Group.

PropTypeDefaultDescription
labelunknown-Label content displayed next to radio.
descriptionunknown-Description text displayed below the label when using card appearance.
valuestring-Native radio value.
namestring-Native radio group name. Radios with the same name are mutually exclusive.
checkedboolean-Whether the radio is initially checked.
disabledboolean-Whether the radio is disabled.
variant"default" | "error""default"Visual variant.
appearance"default" | "card""default"Visual appearance.
controlPosition"start" | "end"-Position of the radio control relative to the label.
classstring-Additional CSS classes for the label wrapper.
classNamestring-Alias for class.

Accessibility

Semantic HTML

Radio.Group uses semantic <fieldset> and <legend> elements for proper grouping and screen reader announcement.

Keyboard Navigation

Because Areia radio items use native <input type="radio">, browsers provide standard keyboard behavior. Tab moves focus to and from the radio group, arrow keys move between radios in the same named group, and Space selects the focused option.

Screen Readers

Each radio is announced with its label and selection state. The group legend provides context for all options.