Switch
An on/off toggle built on the native <input type="checkbox">, carrying the
shared root field composition.
Usage
<input is="root-switch" type="checkbox" data-label="Enable notifications" />
The composition comes from fieldDecorator, the same one Input, Checkbox and Radio use: a
[field-wrapper] span draws the track and the knob, 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.
<label>
<span data-part="label">Enable notifications</span>
<span field-wrapper>
<input is="root-switch" type="checkbox" switch role="switch" sr-only />
</span>
</label>
Switch semantics
The component sets the platform's switch attribute and
role="switch" on itself, so the state is announced as on/off rather than
checked/unchecked. checked stays the property and attribute that carries it, and form
participation is the checkbox's own.
<input is="root-switch" type="checkbox" data-label="Dark mode" checked />
Indeterminate
The indeterminate attribute reflects onto the native .indeterminate property -
announced as aria-checked="mixed" - and parks the thumb mid-travel on a resting
track, so "not decided" cannot be read as on. A user toggle resolves it, clearing the attribute.
<input is="root-switch" type="checkbox" indeterminate data-label="Sync settings" />
States
Off is a Neutral 400 track with the thumb at the near end; on slides it to the far end and moves the track
to Default 400. Hover and :active walk one and two ramp steps deeper on whichever of the two
it is, and the whole label is the target.
disabled
leaves both ramps for Neutral 200.
<input is="root-switch" type="checkbox" data-label="Off" />
<input is="root-switch" type="checkbox" data-label="On" checked />
<input is="root-switch" type="checkbox" data-label="Focused" data-demo="focus" />
<input is="root-switch" type="checkbox" data-label="Focused, on" checked data-demo="focus" />
<input is="root-switch" type="checkbox" data-label="Disabled" disabled />
<input is="root-switch" type="checkbox" data-label="Disabled, on" checked disabled />
The middle pair wears the focus ring without being focused: data-demo="focus" is
the docs' own marker, and Focus says what it draws.
Sizes
data-size
takes small, medium and large; medium is the default and needs no
value written. The track measures 43x24 / 36x20 / 29x16px and the thumb is its height less four, inset by
two - so the travel is what is left: 19 / 16 / 13px. The label follows: the md type step at
large and medium, sm at small.
<input is="root-switch" type="checkbox" data-size="large" data-label="Large" checked />
<input is="root-switch" type="checkbox" data-label="Medium" checked />
<input is="root-switch" type="checkbox" data-size="small" data-label="Small" checked />
Description
data-hint
puts a description under the label, indented past the track so it sits under the text and reads as this
control's rather than the next one's.
<input
is="root-switch"
type="checkbox"
data-label="Weekly digest"
data-hint="One message on Monday, with what changed."
checked
/>
Label placement
The label sits after the track 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-switch" type="checkbox" data-label="Above the track" data-label-position="block-start" />
<input is="root-switch" type="checkbox" data-label="After the track" data-label-position="inline-end" />
<input is="root-switch" type="checkbox" data-label="Below the track" data-label-position="block-end" />
<input is="root-switch" type="checkbox" data-label="Before the track" 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.
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:
<input is="root-switch" type="checkbox" data-label="Focused" data-demo="focus" />
<input is="root-switch" type="checkbox" data-label="Focused, on" checked data-demo="focus" />
data-invalid
sets aria-invalid on the control; data-error replaces the description with the
message while it is set.
<input is="root-switch" type="checkbox" required data-label="Accept the terms" data-invalid="true" />
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
type |
'checkbox' |
'checkbox' |
Input type |
checked |
boolean |
false |
Toggle state |
disabled |
boolean |
false |
Disables the switch |
data-label |
string |
- | Label text; the component builds the <label> |
required |
boolean |
false |
Marks the field required and draws the asterisk |
indeterminate |
boolean |
false |
Mixed state (thumb mid-travel + aria-checked="mixed"); cleared on toggle
|
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, no message is rendered |
Parts
| Part | Description |
|---|---|
[field-wrapper] |
Draws the track and the knob |
[data-part="label"] |
The label text, holding the required marker |
Events
Namespaced as <component>.<event>, bubbling and cancelable;
detail also carries the originating DOM event as originalEvent.
| Event | Detail | Description |
|---|---|---|
root-switch.input |
{ value } |
Fired on input |
root-switch.change |
{ value } |
Fired on change |
root-switch.focus |
{ value } |
Fired on focus |
root-switch.blur |
{ value } |
Fired on blur |
root-switch.invalid |
{ value } |
Fired when the control fails constraint validation |
root-switch.data-label.change |
{ value, oldValue } |
Fired when the label text changes |
Extends
HTMLInputElement - use with <input is="root-switch">.