Skip to content

CSS

A toggle is a switch control that lets users turn a setting on or off. Put tng-toggle-control on a wrapper holding a native <input type="checkbox"> and its label — wrap the input in a <label> as below, or keep them siblings inside a <div> and wire them with for / id. Everything the switch renders comes off that one input: the track is its background, and the thumb and the cross / check glyph are its ::before and ::after.

<label class="tng-toggle-control">
<input type="checkbox" />
<span>Off</span>
</label>
<label class="tng-toggle-control">
<input type="checkbox" checked />
<span>On</span>
</label>

The switch is one fixed size. tng-toggle-control rides the body type scale, so the is-* typography modifiers resize the label only — the default is body-6, and is-7 is the smaller label Figma calls Size=Small.

<label class="tng-toggle-control">
<input type="checkbox" checked />
<span>Default label</span>
</label>
<label class="tng-toggle-control is-7">
<input type="checkbox" checked />
<span>Small label</span>
</label>

Use the native disabled attribute. It mutes the track, sets cursor: not-allowed on the whole control, and takes the switch out of the tab order.

<label class="tng-toggle-control">
<input type="checkbox" disabled />
<span>Off and disabled</span>
</label>
<label class="tng-toggle-control">
<input type="checkbox" checked disabled />
<span>On and disabled</span>
</label>

A checkbox whose indeterminate IDL property is true parks the thumb halfway along the track. There is no HTML attribute for it — set it from script, and only where “partially on” is a state the setting really has (a parent switch over a group of sub-settings). Note that this state has no equivalent under role="switch", which admits only on and off.

document.querySelector('#sync').indeterminate = true;

Add is-error to the control to recolour the label and draw the error ring around the switch. The same treatment applies on its own when the input is :invalid — a required switch the user hasn’t turned on, for instance — so constraint validation needs no extra class. Either way the treatment steps aside while the switch has focus, so the focus ring stays legible. is-error is a visual cue only; see the Accessibility tab for the aria-invalid and aria-describedby wiring that carries it to assistive technology.

<label class="tng-toggle-control is-error">
<input type="checkbox" />
<span>Off with an error</span>
</label>
<label class="tng-toggle-control is-error">
<input type="checkbox" checked />
<span>On with an error</span>
</label>