20 Pure CSS Toggles & Switches
Industrial Rocker
A chunky industrial rocker switch with twin indicator lights, rotating "teeth" along the rail, and a color-shifting metallic thumb. The off-light glows red; the on-light glows brand purple. Inspired by heavy-duty equipment power switches.
Industrial Rocker the 20th of 20 designs in the 20 Pure CSS Toggles & Switches collection. The design is implemented in pure CSS — no JavaScript required. Copy the HTML and CSS panels below into your project. Because the demo is pure CSS, it works in any framework or templating engine you happen to use. The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<label class="tg-rock">
<input class="tg-rock-input" type="checkbox" checked>
<span class="tg-rock-body" aria-hidden="true">
<span class="tg-rock-lights">
<span class="tg-rock-light tg-rock-light-off"></span>
<span class="tg-rock-light tg-rock-light-on"></span>
</span>
<span class="tg-rock-track-top">
<span></span><span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span><span></span>
</span>
<span class="tg-rock-rail"></span>
<span class="tg-rock-thumb"></span>
<span class="tg-rock-track-bot">
<span></span><span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span><span></span>
</span>
</span>
<span class="tg-rock-label">Power</span>
</label> @property --tg-rock-shine {
syntax: "<color>";
initial-value: #f50000;
inherits: false;
}
.tg-rock {
--tg-rock-sz: 8px;
--tg-rock-off: #f50000;
--tg-rock-on: #7c6cff;
display: inline-flex;
align-items: center;
gap: 18px;
cursor: pointer;
font-family: "Inter", "Segoe UI", system-ui, sans-serif;
font-size: 14px;
color: #1a1a2e;
user-select: none;
}
.tg-rock-input {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden; clip: rect(0,0,0,0);
white-space: nowrap; border: 0;
}
/* Body proportions: 28×sz wide, 18×sz tall.
Layout regions stacked vertically:
row 1 (top): lights row, ~3×sz tall
row 2: top track teeth, ~1.5×sz tall
row 3: rail + thumb, ~7×sz tall (the main switch)
row 4: bottom track teeth, ~1.5×sz tall */
.tg-rock-body {
position: relative;
display: inline-block;
width: calc(var(--tg-rock-sz) * 28);
height: calc(var(--tg-rock-sz) * 18);
}
.tg-rock-lights {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: calc(var(--tg-rock-sz) * 2);
}
.tg-rock-light {
width: calc(var(--tg-rock-sz) * 1.4);
height: calc(var(--tg-rock-sz) * 1.4);
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #4a4a52, #1a1a1f);
box-shadow: inset 0 1px 2px rgba(0,0,0,0.6);
transition: all 0.5s ease;
}
/* Rail spans the full body width, vertically centered. */
.tg-rock-rail {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: calc(var(--tg-rock-sz) * 7);
transform: translateY(-50%);
background: linear-gradient(180deg, #2a2a30, #0a0a0e);
border-radius: calc(var(--tg-rock-sz) * 0.8);
box-shadow:
inset 0 2px 6px rgba(0,0,0,0.8),
inset 0 -1px 2px rgba(255,255,255,0.05),
0 2px 4px rgba(0,0,0,0.3);
}
/* Thumb: ~12×sz wide (almost half the body), 6×sz tall, sits on the rail. */
.tg-rock-thumb {
position: absolute;
top: 50%;
left: calc(var(--tg-rock-sz) * 1);
width: calc(var(--tg-rock-sz) * 12);
height: calc(var(--tg-rock-sz) * 5.5);
transform: translateY(-50%);
background: linear-gradient(180deg, #c0c0c8 0%, #8a8a92 45%, #4a4a52 100%);
border-radius: calc(var(--tg-rock-sz) * 0.6);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.5),
inset 0 -2px 4px rgba(0,0,0,0.5),
0 3px 6px rgba(0,0,0,0.5),
0 0 calc(var(--tg-rock-sz) * 1.8) var(--tg-rock-shine);
transition: left 0.5s ease, --tg-rock-shine 0.5s ease;
}
/* Grip lines: three horizontal bars across the thumb face. */
.tg-rock-thumb::before {
content: "";
position: absolute;
top: 50%;
left: 25%;
right: 25%;
height: 1px;
transform: translateY(-50%);
background: rgba(0,0,0,0.55);
box-shadow:
0 calc(var(--tg-rock-sz) * 0.6) 0 rgba(0,0,0,0.55),
0 calc(var(--tg-rock-sz) * -0.6) 0 rgba(0,0,0,0.55);
}
.tg-rock-track-top,
.tg-rock-track-bot {
position: absolute;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding: 0 calc(var(--tg-rock-sz) * 1);
}
.tg-rock-track-top { top: calc(var(--tg-rock-sz) * 3); }
.tg-rock-track-bot { bottom: calc(var(--tg-rock-sz) * 0); }
.tg-rock-track-top span,
.tg-rock-track-bot span {
width: calc(var(--tg-rock-sz) * 1);
height: calc(var(--tg-rock-sz) * 1);
background: #3a3a42;
border-radius: 1px;
transition: transform 0.5s ease;
}
/* Off state — left light glows red. */
.tg-rock-light-off {
background: radial-gradient(circle at 35% 35%, #ff7575, var(--tg-rock-off));
box-shadow:
inset 0 1px 1px rgba(255,255,255,0.3),
0 0 calc(var(--tg-rock-sz) * 1.2) var(--tg-rock-off);
}
/* On state — left dims, right lights up purple, thumb slides right. */
.tg-rock-input:checked ~ .tg-rock-body .tg-rock-light-off {
background: radial-gradient(circle at 35% 35%, #4a4a52, #1a1a1f);
box-shadow: inset 0 1px 2px rgba(0,0,0,0.6);
}
.tg-rock-input:checked ~ .tg-rock-body .tg-rock-light-on {
background: radial-gradient(circle at 35% 35%, #b5a8ff, var(--tg-rock-on));
box-shadow:
inset 0 1px 1px rgba(255,255,255,0.3),
0 0 calc(var(--tg-rock-sz) * 1.2) var(--tg-rock-on);
}
.tg-rock-input:checked ~ .tg-rock-body .tg-rock-thumb {
left: calc(100% - var(--tg-rock-sz) * 13);
--tg-rock-shine: #7c6cff;
}
.tg-rock-input:checked ~ .tg-rock-body .tg-rock-track-top span {
transform: rotate(20deg);
}
.tg-rock-input:checked ~ .tg-rock-body .tg-rock-track-bot span {
transform: rotate(-20deg);
}
.tg-rock-input:focus-visible ~ .tg-rock-body .tg-rock-rail {
outline: 2px solid #7c6cff;
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
.tg-rock-thumb,
.tg-rock-light,
.tg-rock-track-top span,
.tg-rock-track-bot span { transition: none; }
}