Tessera UI

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.

Installation

pnpm add @tessinaui/ui

Usage

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>

Playground

Preview
Loading...

Showcase

Preview
Loading...

API Reference

Radio props

PropTypeDefaultDescription
valuestring""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
disabledbooleanfalsePrevents interaction
readOnlybooleanfalsePrevents interaction, accessible
requiredbooleanfalseHTML required + asterisk on label
labelstringText label rendered beside the radio
descriptionstringHelper text below the label
errorMessagestringError text (overrides description, adds AlertCircle)
labelPosition"left" | "right""right"Which side the label appears on
dir"ltr" | "rtl"Text direction for the wrapper
namestringInput name for form submission
classNamestringExtra classes on the wrapper <div>

All other native attributes are forwarded to the underlying <span> (Base UI).

RadioGroup props

PropTypeDefaultDescription
valuestringControlled selected value
defaultValuestringUncontrolled initial value
onValueChange(value: string) => voidChange handler
disabledbooleanfalseDisables all radios in the group
orientation"vertical" | "horizontal""vertical"Stack direction
variant"filled" | "outline""filled"Propagated to child Radios
sizeRadioSize"md"Propagated to child Radios
intentRadioIntent"none"Propagated to child Radios
labelstringGroup legend
descriptionstringHelper text below legend
errorMessagestringError text for the group
requiredbooleanfalseAsterisk on group legend
dir"ltr" | "rtl"Text direction for the group wrapper

RadioCard props

PropTypeDefaultDescription
valuestring""Value submitted with the form
titlestringCard title (required)
descriptionstringOptional description below the title
iconReactNodeLeading icon rendered left of the text
sizeRadioSize"md"Size of the radio indicator
intentRadioIntent"none"Semantic color
disabledbooleanfalsePrevents interaction
dir"ltr" | "rtl"Text direction

RadioCardGroup props

PropTypeDefaultDescription
valuestringControlled selected value
defaultValuestringUncontrolled initial value
onValueChange(value: string) => voidChange handler
columns1 | 2 | 3 | 42Number of card columns
sizeRadioSize"md"Propagated to child RadioCards
intentRadioIntent"none"Propagated to child RadioCards
disabledbooleanfalseDisables all cards
labelstringGroup legend
descriptionstringHelper text
errorMessagestringError text for the group

States

StateVisual
UnselectedEmpty ring with border
SelectedRing + filled inner dot
Disabled unselectedMuted empty ring
Disabled selectedMuted ring + muted dot
FocusRing outline (2px)
Hover (unselected)Darker border
Hover (selected)Slightly darker border

Sizes

SizeRingDot
xs14×14 px6×6 px
sm16×16 px8×8 px
md20×20 px10×10 px
lg24×24 px12×12 px
xl28×28 px14×14 px

Intents

IntentUnselected borderSelected ring/dot
noneborder-borderborder-primary / bg-primary
errorborder-errorborder-error / bg-error
warningborder-warningborder-warning / bg-warning
successborder-successborder-success / bg-success
infoborder-infoborder-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-invalid set on group when errorMessage is present
  • aria-describedby links error messages to their respective controls
  • Required: aria-required + native required attribute 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

On this page