All components
Forms
Radio
stable
Since 1.1
A single composable radio control, for rows that need custom content beyond a flat label and description.
Forms
primitive
Display
Documented
import { Radio } from '@ivim/native/components';
When to use
Use when
A radio row needs custom content — a price, a badge, a trailing control — that an options array cannot express.
You are building a bespoke choice layout and want the control without the group chrome.
Don't use when
The options are a plain list of labels and descriptions — use RadioGroup, which handles exclusivity and the group name for you.
The options should read as cards — use SelectableCardGroup.
More than one option may be chosen — use Checkbox.
Playground
Adjust the controls to preview live prop combinations. The code snippet updates to match the current selection.
Monthly
Annual
size
size
sm
md
Invalid
isInvalid
Disabled
isDisabled
<Radio />
Example
Preview
Code
Composed set
Operable pair (parent owns the value)
Monthly
Annual
Small
Monthly
Annual
Individual states
Selected
Monthly
Unselected
Annual
With description
Annual
Billed once a year, save 20%.
With a tooltip
Annual
Invalid
Choose a plan
Read only (still announced as enabled)
Set by your plan
Disabled
Unavailable
Custom row content
Label as a custom node
Enterprise$99 / month
Anatomy
The parts that compose this component.
1
Control
The circle carrying border and fill.
2
Dot
Inner fill shown when selected; animates in.
3
Label
The option text, and the accessible name.
4
Description
Supporting text beneath the label; takes the error color when invalid.
Guidelines
Do
Own the selected value in the parent and pass isSelected to each radio — a lone Radio has no notion of its siblings.
Do
Give every radio in a set the same group context in its accessible name, as RadioGroup does automatically.
Don't
Render a single radio on its own — a choice of one cannot be deselected and should be a checkbox.
Props
Public props for this component. Required props are marked; defaults reflect the component implementation.
value
required
string
Value reported through onChange when this radio is chosen.
isSelected
boolean
default: false
Whether this radio is the chosen one. Owned by the parent.
onChange
(value: string) => void
Fires with this radio’s value on press.
label / description
ReactNode
Option text and supporting text.
tooltip
string
Contextual help behind a small info affordance beside the row. Supplementary only — anything required to act belongs in description.
isDisabled
boolean
default: false
Dims, blocks input, and announces disabled.
isReadOnly
boolean
default: false
Blocks input but still announces as an enabled control.
isInvalid
boolean
default: false
Applies the error treatment.
size
'sm' | 'md'
default: 'md'
Control and label scale.
isTabbable / onKeyDown
boolean / (event) => void
Roving-tabindex position and web key handler. RadioGroup sets both so the group is one tab stop with arrow-key selection; a lone Radio rarely needs them.
aria-label
string
Accessible name when there is no visible label, or when the label is not plain text.
Deviations from Untitled UI
Where this component deliberately differs from Untitled UI's API, and why. These are kept choices, not gaps to close.
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.
Accessibility
Roles and screen-reader behavior this component provides, plus keyboard interactions.
•
Announces accessibilityRole="radio" with checked state — the previous implementation set no role at all, so radios announced as plain pressables.
•
Takes its name from a string label, or from aria-label when the label is not plain text.
•
Read-only rejects input while still announcing as an enabled control.
•
Exclusivity is not enforced here: a lone Radio reports only its own state, so the parent or RadioGroup must guarantee one-of-many.
Tab
Moves focus to the radio.
Space
Selects the focused radio.
Arrow keys
Not handled by a lone Radio — RadioGroup owns arrow-key traversal.
Platform & RTL
Behavior that differs across the platforms this component runs on.
Web
Focusable with a visible inset focus ring matched to the circular radius.
iOS
VoiceOver announces the radio trait and its selected state.
Android
TalkBack announces the radio trait and its selected state.
RTL
The control and label swap sides with the writing direction.
State coverage
Interaction and visual states this component supports.
base
semantic color
density
Token references
Semantic design tokens this component page exercises. Tap one to edit it live.
Related components
Components that solve adjacent problems or compose with this one.
RadioGroup
One-of-many choice as a list or as selectable cards, with icon, avatar, price, badge, and secondary-action slots.
Checkbox
Independent on/off choice with indeterminate, invalid, and read-only states, plus a CheckboxGroup for related options.
Toggle
On/off switch with three sizes, a slim treatment, label and description composition, and read-only and invalid states.
ButtonGroup
Joined group of adjacent segments: an action group, or a single- or multiple-selection control with group and per-item disabled states.