Radio
One of a set, built on the native <input type="radio">, rendered as
<input is="root-radio">.
Usage
<input is="root-radio" type="radio" name="option" value="a" data-label="Option A" />
<input is="root-radio" type="radio" name="option" value="b" data-label="Option B" />
Groups
A group is implicit: every radio sharing a name is one, which is what the platform already
enforces - single selection and arrow-key roving come free. There is no group component. Give the group a
visible name the native way, with a <fieldset> and a
<legend>; the radios inside expose it as
role="radiogroup" themselves, and
[direction="horizontal"]
lays them on one line.
<fieldset>
<legend>Choose a plan</legend>
<input is="root-radio" type="radio" name="plan" value="free" data-label="Free" />
<input is="root-radio" type="radio" name="plan" value="pro" data-label="Pro" />
<input is="root-radio" type="radio" name="plan" value="team" data-label="Team" />
</fieldset>
<fieldset direction="horizontal">
<legend>Billing</legend>
<input is="root-radio" type="radio" name="billing" value="monthly" data-label="Monthly" />
<input is="root-radio" type="radio" name="billing" value="yearly" data-label="Yearly" />
</fieldset>
The group property returns the radios a given one is grouped with - same name,
same form, itself included.
The field composition is the shared one (fieldDecorator): a [field-wrapper]
span draws the dot, the native input stays in the DOM as [sr-only] - still the focus target
and still what assistive tech reads - and data-label, data-hint,
required
and data-invalid behave as they do on Input.
States
Unchecked is the page ground with a Neutral 400 ring; checked moves the ring into Default 400 and shows a
dot at half the control. One name is one answer, so the disabled pair below is a group of its
own - two checked radios sharing a name means the last one wins and the first renders
unchecked. It never fills, which is what separates it from a checkbox. Hover and :active walk
one and two ramp steps deeper, and the whole label is the target.
<fieldset>
<legend>State</legend>
<input is="root-radio" type="radio" name="state" value="off" data-label="Unchecked" />
<input is="root-radio" type="radio" name="state" value="on" data-label="Checked" checked />
</fieldset>
<fieldset>
<legend>Focus</legend>
<input is="root-radio" type="radio" name="state-focus" value="off" data-label="Focused" data-demo="focus" />
<input is="root-radio" type="radio" name="state-focus" value="on" data-label="Focused, checked" checked data-demo="focus" />
</fieldset>
<fieldset>
<legend>Disabled</legend>
<input is="root-radio" type="radio" name="state-disabled" value="off" data-label="Disabled" disabled />
<input is="root-radio" type="radio" name="state-disabled" value="on" data-label="Disabled, checked" checked disabled />
</fieldset>
Sizes
data-size
takes small, medium and large; medium is the default and needs no
value written. The control measures 24 / 20 / 16px with a dot at half of that, and small drops to a 1px
ring - at 16px a 2px one eats the control. The label follows: the md type step at large and
medium, sm at small.
<fieldset>
<legend>Size</legend>
<input is="root-radio" type="radio" name="size" value="lg" data-size="large" data-label="Large" checked />
<input is="root-radio" type="radio" name="size" value="md" data-label="Medium" />
<input is="root-radio" type="radio" name="size" value="sm" data-size="small" data-label="Small" />
</fieldset>
Description
data-hint
puts a description under the label, indented past the control so it sits under the text and reads as this
option's rather than the next one's.
<fieldset>
<legend>Plan</legend>
<input
is="root-radio"
type="radio"
name="tier"
value="free"
data-label="Free"
data-hint="One project, community support."
checked
/>
<input
is="root-radio"
type="radio"
name="tier"
value="pro"
data-label="Pro"
data-hint="Unlimited projects, and a person to email."
/>
</fieldset>
Label placement
The label sits after the dot by default. data-label-position moves it to any of the four
sides - inline-start, block-start, inline-end (the default),
block-end
- logically, so the sides follow the writing mode.
All four below, clockwise from the top, stacked in a <fieldset>: the group is the
component's own (see above), and it lays its rows out in a column - which is what lets the two block
placements be read as above and below rather than as two columns that happen to be
taller than the rest of the row.
<fieldset>
<input is="root-radio" type="radio" name="placement" data-label="Above the dot" data-label-position="block-start" />
<input is="root-radio" type="radio" name="placement" data-label="After the dot" data-label-position="inline-end" />
<input is="root-radio" type="radio" name="placement" data-label="Below the dot" data-label-position="block-end" />
<input is="root-radio" type="radio" name="placement" data-label="Before the dot" data-label-position="inline-start" />
</fieldset>
Focus
The ring is the foundations', drawn around the wrapper: the input is [sr-only] but never
hidden, so it is what takes focus and _focus.css is what draws it. Inside a group the arrow
keys move it, which is the platform's own behavior.
Focus only exists while something has it, so a page cannot show it by asking. Marked
data-demo="focus"
- the docs' own attribute, not a component one - the example below wears the same ring, from the same
tokens, on the element the real one lands on:
<fieldset direction="horizontal">
<legend>Focus</legend>
<input is="root-radio" type="radio" name="focus" value="off" data-label="Focused" data-demo="focus" />
<input is="root-radio" type="radio" name="focus" value="on" data-label="Focused, checked" checked data-demo="focus" />
</fieldset>
data-invalid
sets aria-invalid on the control; data-error replaces the description with the
message while it is set.
<input is="root-radio" type="radio" name="plan" value="pro" data-label="Pro" data-invalid="true" />
Properties
| Property | Type | Description |
|---|---|---|
group |
HTMLInputElement[] |
The radios sharing this one's name, in document order |
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
type |
'radio' |
'radio' |
Input type |
name |
string |
- | Radio group name |
checked |
boolean |
false |
Checked state |
disabled |
boolean |
false |
Disables the input |
data-size |
'small' | 'medium' | 'large' |
'medium' |
Control, dot, ring and type step |
data-label |
string |
- | Label text; the component builds the <label> |
data-hint |
string |
- | Description under the label |
required |
boolean |
false |
Marks the field required and draws the asterisk |
data-label-position |
'inline-start' | 'block-start' | 'inline-end' | 'block-end' |
'inline-end' |
Which side the label text sits on |
data-invalid |
'true' |
- | Marks the control invalid: sets aria-invalid |
data-error |
string |
- | Message shown in place of the description while invalid |
Events
| Event | Detail | Description |
|---|---|---|
root-radio.input |
{ value } |
Fired on input |
root-radio.change |
{ value } |
Fired on change |
root-radio.focus |
{ value } |
Fired on focus |
root-radio.blur |
{ value } |
Fired on blur |
root-radio.invalid |
{ value } |
Fired on validation failure |
root-radio.data-label.change |
{ value, oldValue } |
Fired when the label text changes |
Extends
HTMLInputElement - use with <input is="root-radio">.