data-switch
Transform a checkbox into a sliding toggle switch with optional size variants. Add data-switch to any checkbox for accessible on/off controls.
Overview
The data-switch attribute transforms a native <input type="checkbox"> into a sliding toggle switch. No wrapper element needed — just add the attribute directly to the checkbox.
<label> <input type="checkbox" data-switch> Enable notifications</label>
How It Works
Add data-switch to any <input type="checkbox">. The init script:
- Sets
appearance: noneon the checkbox to remove native styling - Renders a track and sliding knob via CSS pseudo-elements
- Adds
role="switch"to the element for proper semantics - Responds to the
checkedstate with a slide transition - Sets
data-switch-initto prevent double-binding
The underlying checkbox remains a real form control. It submits with the form, supports validation, and fires native change events.
Attributes
| Attribute | Values | Description |
|---|---|---|
data-switch |
"", "sm", "lg" |
Transforms the checkbox into a toggle switch. Value sets the size variant (default: standard). |
data-switch-init |
boolean | Set automatically to prevent double-binding. Do not set manually. |
Size Variants
Three size variants are available via the attribute value: sm (small), default (empty string), and lg (large). The track and knob scale proportionally.
<label> <input type="checkbox" data-switch="sm"> Small switch</label> <label> <input type="checkbox" data-switch> Default switch</label> <label> <input type="checkbox" data-switch="lg"> Large switch</label>
With Form Field
Wrap in <form-field> for validation feedback, helper text, and required indicators. The switch works seamlessly with form-field's validation lifecycle.
<form-field> <label> <input type="checkbox" data-switch required> Accept terms and conditions </label> <small slot="help">You must agree before continuing.</small></form-field>
Checked by Default
Add the native checked attribute to render the switch in the on position initially.
<label> <input type="checkbox" data-switch checked> Enabled by default</label>
Disabled and Read-only
Native disabled and readonly attributes are fully supported. Disabled switches are visually muted and non-interactive. Read-only switches display their current state but cannot be toggled.
<label> <input type="checkbox" data-switch disabled> Disabled off</label> <label> <input type="checkbox" data-switch disabled checked> Disabled on</label> <label> <input type="checkbox" data-switch readonly checked> Read-only on</label>
Settings Group
Combine multiple switches in a <fieldset> for grouped settings panels.
<fieldset> <legend>Notification preferences</legend> <label> <input type="checkbox" data-switch checked> Email notifications </label> <label> <input type="checkbox" data-switch> SMS notifications </label> <label> <input type="checkbox" data-switch checked> Push notifications </label></fieldset>
Styling
The switch track and knob are fully customizable via CSS custom properties. All styles are gated on [data-switch-init] so the checkbox renders normally without JavaScript.
/* Track */[data-switch][data-switch-init] { --switch-track-width: 2.5rem; --switch-track-height: 1.375rem; --switch-track-bg: var(--color-border); --switch-track-bg-checked: var(--color-primary); --switch-track-radius: var(--radius-pill);} /* Knob */[data-switch][data-switch-init] { --switch-knob-size: 1rem; --switch-knob-bg: white; --switch-knob-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);}
The :checked pseudo-class controls the knob position and track color. Transitions use prefers-reduced-motion to disable animation when requested.
Dynamic Elements
Switches added to the DOM after page load are automatically enhanced via a MutationObserver. No manual initialization is needed.
<section> <h2>Accessibility</h2> <ul> <li><code>role="switch"</code> is added automatically, announcing the control as a toggle switch to screen readers</li> <li>Keyboard toggle with <kbd>Space</kbd> works natively since the underlying element is a real checkbox</li> <li>A visible <code><label></code> is required — always wrap the switch in a label or use <code>aria-label</code></li> <li><code>disabled</code> and <code>readonly</code> states are conveyed to assistive technology via native attributes</li> <li>Focus ring follows the system focus style via <code>:focus-visible</code></li> <li><code>prefers-reduced-motion</code>: slide transitions are disabled when the user prefers reduced motion</li> <li>Without JavaScript, the checkbox renders normally — progressive enhancement</li> </ul> </section>