ComponentsForm Blocks
Radio
A form control that lets users select exactly one option from a group. Five sizes, five intents, label/description/error patterns, RadioGroup compound component, and RadioCard full-surface variant.
Playground
Installation
pnpm add @tessinaui/uiUsage
import { Radio, RadioGroup } from "@tessinaui/ui";{/* Uncontrolled group */}
<RadioGroup defaultValue="email" label="Contact method">
<Radio value="email" label="Email" />
<Radio value="sms" label="SMS" />
<Radio value="phone" label="Phone" />
</RadioGroup>
{/* Controlled group */}
<RadioGroup value={method} onValueChange={setMethod} label="Contact method">
<Radio value="email" label="Email" />
<Radio value="sms" label="SMS" />
</RadioGroup>
{/* With error */}
<RadioGroup required errorMessage="Please select an option.">
<Radio value="a" label="Option A" intent="error" />
<Radio value="b" label="Option B" intent="error" />
</RadioGroup>Showcase
API Reference
Radio props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | "" | Value submitted with the form (required for group behavior) |
variant | "filled" | "outline" | "filled" | Unchecked style: filled has bg-secondary, outline is transparent |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Visual size of the radio indicator |
intent | "none" | "error" | "warning" | "success" | "info" | "none" | Semantic color for ring and dot |
disabled | boolean | false | Prevents interaction |
readOnly | boolean | false | Prevents interaction, accessible |
required | boolean | false | HTML required + asterisk on label |
label | string | — | Text label rendered beside the radio |
description | string | — | Helper text below the label |
errorMessage | string | — | Error text (overrides description, adds AlertCircle) |
labelPosition | "left" | "right" | "right" | Which side the label appears on |
dir | "ltr" | "rtl" | — | Text direction for the wrapper |
name | string | — | Input name for form submission |
className | string | — | Extra classes on the wrapper <div> |
All other native attributes are forwarded to the underlying <span> (Base UI).
RadioGroup props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled selected value |
defaultValue | string | — | Uncontrolled initial value |
onValueChange | (value: string) => void | — | Change handler |
disabled | boolean | false | Disables all radios in the group |
orientation | "vertical" | "horizontal" | "vertical" | Stack direction |
variant | "filled" | "outline" | "filled" | Propagated to child Radios |
size | RadioSize | "md" | Propagated to child Radios |
intent | RadioIntent | "none" | Propagated to child Radios |
label | string | — | Group legend |
description | string | — | Helper text below legend |
errorMessage | string | — | Error text for the group |
required | boolean | false | Asterisk on group legend |
dir | "ltr" | "rtl" | — | Text direction for the group wrapper |
RadioCard props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | "" | Value submitted with the form |
title | string | — | Card title (required) |
description | string | — | Optional description below the title |
icon | ReactNode | — | Leading icon rendered left of the text |
size | RadioSize | "md" | Size of the radio indicator |
intent | RadioIntent | "none" | Semantic color |
disabled | boolean | false | Prevents interaction |
dir | "ltr" | "rtl" | — | Text direction |
RadioCardGroup props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled selected value |
defaultValue | string | — | Uncontrolled initial value |
onValueChange | (value: string) => void | — | Change handler |
columns | 1 | 2 | 3 | 4 | 2 | Number of card columns |
size | RadioSize | "md" | Propagated to child RadioCards |
intent | RadioIntent | "none" | Propagated to child RadioCards |
disabled | boolean | false | Disables all cards |
label | string | — | Group legend |
description | string | — | Helper text |
errorMessage | string | — | Error text for the group |
States
| State | Visual |
|---|---|
| Unselected | Empty ring with border |
| Selected | Ring + filled inner dot |
| Disabled unselected | Muted empty ring |
| Disabled selected | Muted ring + muted dot |
| Focus | Ring outline (2px) |
| Hover (unselected) | Darker border |
| Hover (selected) | Slightly darker border |
Sizes
| Size | Ring | Dot |
|---|---|---|
xs | 14×14 px | 6×6 px |
sm | 16×16 px | 8×8 px |
md | 20×20 px | 10×10 px |
lg | 24×24 px | 12×12 px |
xl | 28×28 px | 14×14 px |
Intents
| Intent | Unselected border | Selected ring/dot |
|---|---|---|
none | border-border | border-primary / bg-primary |
error | border-error | border-error / bg-error |
warning | border-warning | border-warning / bg-warning |
success | border-success | border-success / bg-success |
info | border-info | border-info / bg-info |
Accessibility
- Hidden
<input type="radio">rendered by Base UI — native form semantics - Arrow keys navigate within a RadioGroup (standard radio group behavior)
aria-invalidset on group whenerrorMessageis presentaria-describedbylinks error messages to their respective controls- Required:
aria-required+ nativerequiredattribute on hidden input - Focus ring visible at all sizes — complies with WCAG 2.1 AA (3:1 contrast)
- Group rendered as
<fieldset>+<legend>for screen reader context
Checkbox
A form control that lets users select one or more options. Supports checked, unchecked, and indeterminate states. Five sizes, five intents, label/description/error patterns, and a CheckboxGroup compound component with select-all support.
Switch
A toggle control that allows users to turn a setting on or off