Radio
A control for choosing exactly one option from a set.
Installation
bash
npx @smicolon/fasla-ui@latest add radioRun init once per project before adding components. See Installation.
Preview
Variants
The layout variant wraps the control and its text in a bordered card, so the whole card becomes the target. Use it when the options carry a description; use the default when they are single words in a tight list.
Sizes
States
Hover and focus are real CSS states rather than props — hover an option, or tab to it, to see them. Selection is carried by the dot alone; the card chrome does not change.
Accessibility
- Renders a native
<input type="radio">, so arrow-key navigation and form submission work without extra code. - Options sharing a
nameform one group, and only one can be selected. descriptionis linked witharia-describedby; the control graphic is hidden from assistive technology.- Without a
labelordescription, pass anaria-label. - Direction is inherited from
dir, never a prop, so the control can never disagree with the page.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "layout" | "default" | A plain control or a bordered card. |
size | "sm" | "md" | "lg" | "md" | Control size. |
checked | boolean | — | Selected state, with onChange. |
disabled | boolean | false | Disables the option and dims it. |
label | string | — | Label text. |
description | string | — | Secondary line below the label. |
name | string | — | Groups radios into one set. |
value | string | — | Value submitted with the form. |
onChange | (event) => void | — | Called when the option is picked. |
className | string | — | Extra classes for the component. |
Usage
A group — options share a name
tsx
import { Radio } from "@/components/ui/radio"
export function DeliveryOptions() {
return (
<fieldset className="flex flex-col gap-3">
<legend className="mb-2 text-sm font-medium">Delivery</legend>
<Radio name="delivery" value="standard" label="Standard" defaultChecked />
<Radio name="delivery" value="express" label="Express" />
</fieldset>
)
}With a description
tsx
import { Radio } from "@/components/ui/radio"
export function DeliveryOptions() {
return (
<fieldset className="flex flex-col gap-3">
<legend className="mb-2 text-sm font-medium">Delivery</legend>
<Radio
name="delivery"
value="standard"
label="Standard"
description="3–5 business days"
defaultChecked
/>
<Radio
name="delivery"
value="courier"
label="Same-day courier"
description="Arrives before 6pm"
/>
</fieldset>
)
}Bordered card layout
tsx
import { Radio } from "@/components/ui/radio"
export function DeliveryCards() {
return (
<fieldset className="flex flex-col gap-3">
<legend className="mb-2 text-sm font-medium">Delivery</legend>
<Radio variant="layout" name="delivery" value="standard" label="Standard" defaultChecked />
<Radio variant="layout" name="delivery" value="express" label="Express" />
</fieldset>
)
}Controlled
tsx
"use client"
import { useState } from "react"
import { Radio } from "@/components/ui/radio"
export function ControlledDeliveryOptions() {
const [delivery, setDelivery] = useState("standard")
return (
<fieldset className="flex flex-col gap-3">
<legend className="mb-2 text-sm font-medium">Delivery</legend>
<Radio
name="delivery"
value="standard"
label="Standard"
checked={delivery === "standard"}
onChange={(e) => setDelivery(e.target.value)}
/>
<Radio
name="delivery"
value="express"
label="Express"
checked={delivery === "express"}
onChange={(e) => setDelivery(e.target.value)}
/>
</fieldset>
)
}Selected: standard