Radio
A control that allows the user to select one option from a set. Radio items are usually rendered inside a Radio.Group.
Areia's Radio uses DOM primitives: native radio inputs, labels, fieldsets, and legends.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
| Prop | Type | Default | Description |
|---|---|---|---|
legend | unknown | - | Legend content for the group. |
| first argument | unknown[] | - | Radio item markup when no group props are needed. |
| second argument | unknown[] | - | 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. |
error | unknown | - | Error message for the group. |
description | unknown | - | Helper text for the group. |
disabled | boolean | - | Whether all controls in the fieldset are disabled. |
controlPosition | "start" | "end" | - | Position of the radio control relative to the label. |
name | string | - | Native form submission name for grouped radio items. |
class | string | - | Additional CSS classes. |
className | string | - | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
label | unknown | - | Legend content. |
class | string | - | Additional CSS classes. |
className | string | - | Alias for class. |
Radio.Item
Individual radio button within Radio.Group.
| Prop | Type | Default | Description |
|---|---|---|---|
label | unknown | - | Label content displayed next to radio. |
description | unknown | - | Description text displayed below the label when using card appearance. |
value | string | - | Native radio value. |
name | string | - | Native radio group name. Radios with the same name are mutually exclusive. |
checked | boolean | - | Whether the radio is initially checked. |
disabled | boolean | - | 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. |
class | string | - | Additional CSS classes for the label wrapper. |
className | string | - | 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.