Fylgja Input Switch
A switch turns a single setting on or off, and applies immediately rather than on
submit. It is a native <input type="checkbox"> with role="switch", which Fylgja
styles into a track and thumb. Because it is still a checkbox, it takes part in
forms, restores on reload, and keeps its keyboard behavior for free.
Preview
<label class="flex gap-sm">
<input type="checkbox" role="switch" checked />
Email notifications
</label>Usage
- Write a plain
<input type="checkbox" role="switch">and give it a label. No classes are needed; Fylgja styles the control from the attribute. - Wrapping the control in its
<label>(as above) labels it without anid. Use a separate<label for>when the label and the control sit apart in the layout. checkedsets the initial state,disabledgreys the control out.- The track and thumb follow the same variables as a checkbox, so
--control-sizesizes the height and thumb, and--switch-sizesets the width.
Anatomy
| Part | Responsibility |
|---|---|
<input type=checkbox> |
The control, its state, and the submitted value. |
role="switch" |
Announces the state as on/off and triggers Fylgja’s style. |
<label> |
Names the setting the switch controls. |
Accessibility
role="switch"changes how the state is announced, from “checked” to “on” or “off”. Everything else, the tab stop, the Space toggle, and the form value, stays native.- Label the switch by what it turns on, not by its current state. “Email notifications” works, “Notifications are on” does not.
- Do not rely on color alone. The thumb also moves, so the state stays readable without color.
- If flipping the switch triggers a slow save, tell the reader the result in a live region such as a Toast, not with a hidden state change.
Variants
Larger switch
Both size variables cascade, so setting them on a wrapper sizes the control inside it.
<label class="flex gap-sm" style="--control-size: 1.75em; --switch-size: 3em">
<input type="checkbox" role="switch" checked />
Larger switch
</label>Examples
Settings list
A run of switches in a list, each label pushed against its control.
<ul role="list" class="flex-col gap-sm">
<li class="flex gap align">
<label for="switch-replies">Comment replies</label>
<input type="checkbox" role="switch" id="switch-replies" checked />
</li>
<li class="flex gap align">
<label for="switch-digest">Weekly digest</label>
<input type="checkbox" role="switch" id="switch-digest" />
</li>
<li class="flex gap align">
<label for="switch-sms">Text messages</label>
<input type="checkbox" role="switch" id="switch-sms" disabled />
</li>
</ul>FAQ
Why a checkbox instead of a button?
A switch is a two-state control that belongs to a form, so it should submit a value and restore with the form. A checkbox does that natively. The role=switch attribute only changes how it is announced, from "checked" to "on/off".
Does the switch need a submit button?
That depends on your form. A switch inside a settings form that saves on change needs script to send the value. A switch inside a normal form submits like any other checkbox, so nothing extra is required.
How do I make the switch bigger?
Set --control-size for the height of the track and thumb, and --switch-size for the width. Both take any length, so a value such as 1.75em and 3em gives a larger control that still scales with the font size.
Can I put a label on both sides, like Off and On?
Avoid it. Two labels make it ambiguous which one names the control and which one describes the state. Use one label for what the setting does and let the switch itself communicate on or off.