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:

  1. Sets appearance: none on the checkbox to remove native styling
  2. Renders a track and sliding knob via CSS pseudo-elements
  3. Adds role="switch" to the element for proper semantics
  4. Responds to the checked state with a slide transition
  5. Sets data-switch-init to 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.

You must agree before continuing.
<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.

Notification preferences
<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.

// Dynamically added switches are auto-enhanced via MutationObserver const input = document.createElement('input'); input.type = 'checkbox'; input.dataset.switch = ''; document.body.appendChild(input); // input is ready to use — no manual init needed

Accessibility

  • role="switch" is added automatically, announcing the control as a toggle switch to screen readers
  • Keyboard toggle with Space works natively since the underlying element is a real checkbox
  • A visible <label> is required — always wrap the switch in a label or use aria-label
  • disabled and readonly states are conveyed to assistive technology via native attributes
  • Focus ring follows the system focus style via :focus-visible
  • prefers-reduced-motion: slide transitions are disabled when the user prefers reduced motion
  • Without JavaScript, the checkbox renders normally — progressive enhancement