Susegad UI
Register
Theme
Palette

Components

Toggle

A native switch (a checkbox with role="switch") that submits and takes Space with or without JavaScript. Quiet is a plain track and thumb drawn by CSS; warm is the brass tower bolt from a Goan door, sliding into its keeper; playful is a clay diya that lights, its flame flickering only while lit and on screen.

quiet warm playful

Open the live demo npx susegad add toggle

Stands on: Core, Core: components, Engine, Tokens

The prompt

the prompt

On or off, now: a latch on a door, a lamp in a niche.

A native switch: a checkbox with role="switch", so a screen reader says "switch, on" or "off", and it submits with the form like any checkbox, with or without JavaScript. Warm draws the brass tower bolt from a Goan door; playful lights a clay diya.

<link rel="stylesheet" href="susegad/components/toggle/toggle.css">
<script type="module" src="susegad/components/toggle/toggle.js"></script>

<sg-toggle>
  <label><input type="checkbox" role="switch" name="breakfast" value="yes" checked> Breakfast every morning</label>
</sg-toggle>
AttributeValuesWhat it does
seedany wordThe lamp's flicker, so two lamps never flicker in step. Defaults to the label.

The prompt

Make a toggle web component around a real <input type="checkbox" role="switch"> inside its label, so it works without JavaScript and a screen reader calls it a switch. Draw the quiet switch with CSS on the native input: appearance: none, a pill track, and a ::before thumb that slides across when checked, the track filling with the accent and the thumb turning to the on-accent colour. Give it three registers. Quiet: exactly that. Warm: a brass tower bolt from a Goan door, as an aria-hidden SVG over the input: a plate with two screws, a keeper on the right, and a bolt with a handle; off, the bolt is drawn back with the handle up; on, it slides into the keeper and the handle turns down. Drive the slide with a CSS transition on the register's duration and spring, keyed off a data-on attribute, so reduced motion makes it instant with no extra code. Playful: a clay diya; off, a dark wick; on, a flame and a soft glow; while it is lit and on screen, the flame flickers from seeded noise, looping without a jump, and it pauses off screen and holds still under reduced motion. Outline every shape that shows the state in the text colour, so the state is 3:1 against the page even though brass and flame are pale. Size the native input to the drawing so every click lands on it. In forced colours, bring back the native control.

Words to code

When you sayTechniqueWhat happens
role="switch"native firstThe browser exposes a switch with on and off. Written in the HTML it works without JavaScript; the element adds it if a builder forgot.
a ::before thumb that slides acrossCSSThe thumb is translated by the track's width minus its own; the transition uses --sg-dur-quick, which the tokens take to 0.01ms under reduced motion.
slides into the keeper … keyed off data-onCSS transitionThe skin only toggles data-on on the SVG. The bolt group moves 8.5 units, exactly far enough to seat inside the keeper's inner wall (the tests check it), with --sg-dur-calm and --sg-ease-spring.
the handle turns downstate by shapeOff and on are different drawings, not colours: the handle up with a gap before the keeper, or down with the bolt inside it.
flickers from seeded noise, looping without a jumpnoiseflicker(t, seed) gives scale and lean from Perlin noise; flameAnimation samples twelve frames and ends on the first, as a looping Web Animation.
pauses off screencalmThe component base reports visibility; the skin pauses and plays the flame. The browser check scrolls a lit lamp away and sees it paused.
outline every shape that shows the statecontrastBolt, keeper, bowl and flame are stroked in --sg-text, so the state reads at 3:1 or more against any surface while brass and flame stay decorative.
size the native input to the drawinghit areaThe input takes the drawing's size and sits under it in the same grid cell; the drawing has pointer-events: none.

Accessibility

  • A screen reader hears "switch", the label, and "on" or "off". Space toggles it.
  • Use a switch for something that takes effect now or a setting; use a checkbox for a choice sent later. Both submit.
  • Track, thumb and outlines are 3:1 or more in every palette and theme (tested).
  • The flame moves only while lit, on screen, in playful motion. Forced colours: the system control.

Credit

The tower bolt is the iron and brass latch on the teak doors of Goan houses. The diya is the clay oil lamp lit across India. Tier: pan-Indian (the diya) and local (the Goan bolt), both everyday objects.

<sg-toggle> wraps one native <input type="checkbox" role="switch"> and its label. It submits and takes Space with or without JavaScript, and a screen reader calls it a switch.

Use

<link rel="stylesheet" href="susegad/components/toggle/toggle.css">
<script type="module" src="susegad/components/toggle/toggle.js"></script>

<sg-toggle>
  <label><input type="checkbox" role="switch" name="reminder" value="whatsapp" checked> A WhatsApp reminder the day before</label>
</sg-toggle>

When off, a switch sends nothing (like any checkbox). Read it on the server as "present means on".

Attributes and properties

ValuesDefault
seedany string, for the lamp's flickerthe label
registerquiet, warm, playfulinherited
checked (property)boolean; setting it fires input and changethe input's

Registers

LookMotion
quiet (and no JS)a plain track and thumb; on fills the track with the accentthe thumb slides under 200ms
warma brass tower bolt; on, the bolt is in the keeper and the handle is downthe bolt slides on the register's spring
playfula clay diya; on, a flame and a glowthe flame flickers while lit and on screen

Reduced motion: no movement anywhere, the bolt already home, the flame still. Forced colours: the system control.

Accessibility

  • Keyboard: Tab to it, Space to switch.
  • The state is always a shape (thumb side, bolt position, flame) outlined in the text colour, never colour alone.
  • Contrast: track edge, filled track, thumb and outlines are 3:1 or more (WCAG 1.4.11), tested for every palette and theme.

Budget

Behaviour 5.3 KB of 12 KB (toggle.js + toggle.core.js); skins 0.3, 2.2 and 1.6 KB.