47 / 47
All 47 in 47 Tailwind CSS Toggles & Switches
- 01Tailwind iOS-Style Toggle Switch with appearance-none
- 02Tailwind Dark Mode Sun / Moon Theme Switcher
- 03Tailwind Neumorphic Soft-UI Pill Toggle
- 04Tailwind Gooey Liquid Morphing Switch with SVG Filter
- 05Tailwind Bouncy Elastic Physics Toggle (Overshoot Cubic-Bezier)
- 06Tailwind ON / OFF Text Switch with Labels Inside the Track
- 07Tailwind SaaS Pricing Toggle — Monthly / Annually Segmented Pill
- 08Tailwind Mechanical Keycap Toggles with Haptic Feedback
- 09Tailwind Waveform Mute Toggle with Animated EQ Bars
- 10Tailwind Timed Auto-Off Toggle with Conic Countdown Ring
- 11Tailwind Press-and-Hold to Confirm Toggle (Fingerprint Scan)
- 12Tailwind Split-Flap Departure Board Toggle (3D Flip)
- 13Tailwind Permission Toggle Group with :has() Live Status Badge
- 14Tailwind Material Design 3 Switch with State Layer
- 15Tailwind Skeuomorphic Wall Light Switch with Room Relight
- 16Tailwind Neon Cyberpunk Toggle with Clipped Corners
- 17Tailwind Brutalist Snap Toggle with Hard Offset Shadow
- 18Tailwind Day / Night Landscape Scene Switch
- 19Tailwind 3D Flip Card Toggle (rotateY Switch)
- 20Tailwind Sliding Pill Toggle with Label Inside the Thumb
- 21Tailwind Glassmorphism Frosted Toggle with backdrop-blur
- 22Tailwind Rotary Knob Toggle with Brushed-Metal Conic Gradient
- 23Tailwind iOS Settings List with Grouped Toggle Rows
- 24Tailwind Minimal Outline Toggle Drawn in currentColor
- 25Tailwind Squash-and-Stretch Pebble Toggle
- 26Tailwind Industrial Rocker I/O Power Switch
- 27Tailwind Accessible role=switch Toggle with forced-colors Support
- 28Tailwind Macro-Pad Toggle Grid with RGB Underglow
- 29Tailwind Radial VU Meter Mute Toggle
- 30Tailwind Segmented Pip Countdown Auto-Off Toggle
- 31Tailwind Slide-to-Confirm Toggle Rail (Drag or Arrow Keys)
- 32Tailwind Odometer Roll ON / OFF Toggle
- 33Tailwind Master Toggle with Indeterminate Tri-State
- 34Tailwind iOS Control Centre Tile Toggles
- 35Tailwind Material 3 Connected Icon Toggle Buttons
- 36Tailwind Two-Gang Wall Plate with Cumulative Room Light
- 37Tailwind Neon Toggle with Animated Conic Border Light
- 38Tailwind Brutalist Rubber-Stamp Toggle
- 39Tailwind Aurora Night Sky Toggle Switch
- 40Tailwind 3D Rotating Cube Toggle
- 41Tailwind Three-Position Off / Auto / On Selector
- 42Tailwind Liquid Glass Toggle with Specular Highlight
- 43Tailwind Three-Detent Rotary Selector Knob
- 44Tailwind Hardware Slide Switch with Knurled Grip
- 45Tailwind Battery Saver Toggle with Live Fill Meter
- 46Tailwind Morphing Sun-to-Moon Icon Toggle (SVG Stroke)
- 47Tailwind Guarded Kill Switch Under a Flip-Up Safety Cover
Tailwind Guarded Kill Switch Under a Flip-Up Safety Cover
The finale: a red safety cover you must flip up before the switch beneath can be thrown, exactly like the guarded toggles on aircraft panels. Two deliberate actions, a warning strip that wakes up, and closing the cover kills the switch automatically.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="ttg-47 w-full min-h-svh grid place-items-center px-5 py-14 bg-ttg47-bg font-ttg47-mono" aria-label="Guarded kill switch">
<div id="ttg-47-panel" class="relative w-[min(340px,100%)] flex flex-col gap-5 px-7 py-6 rounded-[18px] bg-linear-165 from-ttg47-panelhi to-ttg47-panello shadow-[0_28px_56px_-28px_oklch(0_0_0/0.95),inset_0_1px_0_oklch(1_0_0/0.08)] has-checked:[&_.ttg47-stripe]:animate-ttg47-pulse motion-reduce:has-checked:[&_.ttg47-stripe]:animate-none">
<span aria-hidden="true" class="ttg47-stripe h-1.5 rounded-full opacity-40 [background:repeating-linear-gradient(135deg,var(--color-ttg47-hazard)_0_10px,var(--color-ttg47-panelhi)_10px_20px)]"></span>
<span class="flex flex-col gap-0.5">
<b class="text-[14px] font-bold tracking-[0.16em] text-ttg47-ink">MASTER CUTOFF</b>
<span class="font-ttg47-sans text-[12.5px] text-ttg47-mute">Flip the guard, then throw the switch</span>
</span>
<div class="relative h-28 perspective-[420px]">
<div class="absolute inset-0 flex items-center justify-center gap-4 rounded-xl bg-ttg47-recess shadow-[inset_0_3px_10px_oklch(0_0_0/0.8)]">
<input type="checkbox" id="ttg-47-kill" role="switch" aria-label="Master cutoff" disabled class="appearance-none w-20 h-11 rounded-full bg-ttg47-trackoff relative cursor-pointer transition-[background-color,opacity] duration-300 disabled:opacity-40 disabled:cursor-not-allowed before:content-[''] before:absolute before:top-1 before:left-1 before:w-9 before:h-9 before:rounded-full before:bg-ttg47-thumb before:shadow-[0_2px_6px_oklch(0_0_0/0.6)] before:transition-transform before:duration-300 before:ease-[cubic-bezier(0.25,0.9,0.3,1.1)] checked:bg-ttg47-hazard checked:before:translate-x-9 focus-visible:outline-3 focus-visible:outline-ttg47-focus focus-visible:outline-offset-4 motion-reduce:transition-none motion-reduce:before:transition-none">
<span id="ttg-47-state" class="font-ttg47-sans text-[13px] font-bold tracking-[0.08em] text-ttg47-mute">SAFE</span>
</div>
<input type="checkbox" id="ttg-47-guard" class="peer sr-only" aria-label="Safety cover">
<label for="ttg-47-guard" class="absolute inset-0 grid place-items-center rounded-xl cursor-pointer origin-top bg-linear-to-b from-ttg47-coverhi to-ttg47-coverlo border-2 border-ttg47-coveredge shadow-[0_10px_20px_-8px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.3)] transition-transform duration-[420ms] ease-[cubic-bezier(0.35,1.25,0.5,1)] peer-checked:-rotate-x-[105deg] peer-focus-visible:outline-3 peer-focus-visible:outline-ttg47-focus peer-focus-visible:outline-offset-4 motion-reduce:duration-100">
<span class="flex flex-col items-center gap-1 text-center">
<b class="text-[12px] font-extrabold tracking-[0.2em] text-white">LIFT GUARD</b>
<span class="font-ttg47-sans text-[10.5px] tracking-[0.1em] text-white/80">Two-step arming</span>
</span>
</label>
</div>
<p id="ttg-47-live" aria-live="polite" class="font-ttg47-sans text-[12px] text-ttg47-mute">Guard closed · switch locked</p>
</div>
</section><section class="ttg-47 w-full min-h-svh grid place-items-center px-5 py-14 bg-ttg47-bg font-ttg47-mono" aria-label="Guarded kill switch">
<div id="ttg-47-panel" class="relative w-[min(340px,100%)] flex flex-col gap-5 px-7 py-6 rounded-[18px] bg-linear-165 from-ttg47-panelhi to-ttg47-panello shadow-[0_28px_56px_-28px_oklch(0_0_0/0.95),inset_0_1px_0_oklch(1_0_0/0.08)] has-checked:[&_.ttg47-stripe]:animate-ttg47-pulse motion-reduce:has-checked:[&_.ttg47-stripe]:animate-none">
<span aria-hidden="true" class="ttg47-stripe h-1.5 rounded-full opacity-40 [background:repeating-linear-gradient(135deg,var(--color-ttg47-hazard)_0_10px,var(--color-ttg47-panelhi)_10px_20px)]"></span>
<span class="flex flex-col gap-0.5">
<b class="text-[14px] font-bold tracking-[0.16em] text-ttg47-ink">MASTER CUTOFF</b>
<span class="font-ttg47-sans text-[12.5px] text-ttg47-mute">Flip the guard, then throw the switch</span>
</span>
<div class="relative h-28 perspective-[420px]">
<div class="absolute inset-0 flex items-center justify-center gap-4 rounded-xl bg-ttg47-recess shadow-[inset_0_3px_10px_oklch(0_0_0/0.8)]">
<input type="checkbox" id="ttg-47-kill" role="switch" aria-label="Master cutoff" disabled class="appearance-none w-20 h-11 rounded-full bg-ttg47-trackoff relative cursor-pointer transition-[background-color,opacity] duration-300 disabled:opacity-40 disabled:cursor-not-allowed before:content-[''] before:absolute before:top-1 before:left-1 before:w-9 before:h-9 before:rounded-full before:bg-ttg47-thumb before:shadow-[0_2px_6px_oklch(0_0_0/0.6)] before:transition-transform before:duration-300 before:ease-[cubic-bezier(0.25,0.9,0.3,1.1)] checked:bg-ttg47-hazard checked:before:translate-x-9 focus-visible:outline-3 focus-visible:outline-ttg47-focus focus-visible:outline-offset-4 motion-reduce:transition-none motion-reduce:before:transition-none">
<span id="ttg-47-state" class="font-ttg47-sans text-[13px] font-bold tracking-[0.08em] text-ttg47-mute">SAFE</span>
</div>
<input type="checkbox" id="ttg-47-guard" class="peer sr-only" aria-label="Safety cover">
<label for="ttg-47-guard" class="absolute inset-0 grid place-items-center rounded-xl cursor-pointer origin-top bg-linear-to-b from-ttg47-coverhi to-ttg47-coverlo border-2 border-ttg47-coveredge shadow-[0_10px_20px_-8px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.3)] transition-transform duration-[420ms] ease-[cubic-bezier(0.35,1.25,0.5,1)] peer-checked:-rotate-x-[105deg] peer-focus-visible:outline-3 peer-focus-visible:outline-ttg47-focus peer-focus-visible:outline-offset-4 motion-reduce:duration-100">
<span class="flex flex-col items-center gap-1 text-center">
<b class="text-[12px] font-extrabold tracking-[0.2em] text-white">LIFT GUARD</b>
<span class="font-ttg47-sans text-[10.5px] tracking-[0.1em] text-white/80">Two-step arming</span>
</span>
</label>
</div>
<p id="ttg-47-live" aria-live="polite" class="font-ttg47-sans text-[12px] text-ttg47-mute">Guard closed · switch locked</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}(() => {
const guard = document.querySelector('#ttg-47-guard');
const kill = document.querySelector('#ttg-47-kill');
const state = document.querySelector('#ttg-47-state');
const live = document.querySelector('#ttg-47-live');
if (!guard || !kill || !state || !live) return;
const report = () => {
const armed = kill.checked;
state.textContent = armed ? 'ARMED' : 'SAFE';
state.style.color = armed ? 'var(--color-ttg47-hazard)' : '';
live.textContent = !guard.checked
? 'Guard closed \u00b7 switch locked'
: (armed ? 'Cutoff ARMED \u2014 close the guard to disarm' : 'Guard open \u00b7 switch unlocked');
};
guard.addEventListener('change', () => {
kill.disabled = !guard.checked;
if (!guard.checked) kill.checked = false; // closing the cover always disarms
report();
});
kill.addEventListener('change', report);
report();
})();(() => {
const guard = document.querySelector('#ttg-47-guard');
const kill = document.querySelector('#ttg-47-kill');
const state = document.querySelector('#ttg-47-state');
const live = document.querySelector('#ttg-47-live');
if (!guard || !kill || !state || !live) return;
const report = () => {
const armed = kill.checked;
state.textContent = armed ? 'ARMED' : 'SAFE';
state.style.color = armed ? 'var(--color-ttg47-hazard)' : '';
live.textContent = !guard.checked
? 'Guard closed \u00b7 switch locked'
: (armed ? 'Cutoff ARMED \u2014 close the guard to disarm' : 'Guard open \u00b7 switch unlocked');
};
guard.addEventListener('change', () => {
kill.disabled = !guard.checked;
if (!guard.checked) kill.checked = false; // closing the cover always disarms
report();
});
kill.addEventListener('change', report);
report();
})();Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&family=Plus+Jakarta+Sans:wght@400;500;600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&family=Plus+Jakarta+Sans:wght@400;500;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The guard works because the inner switch is genuinely
disabled, not merely covered:disabled:opacity-40 disabled:cursor-not-allowedis the visible half, and the attribute is the real half. A guard that only occludes is theatre. - Closing the cover forces the switch off, which is the behaviour of the hardware this imitates and the reason the pattern is trusted — the panel can never look safe while being armed.
- Two nested controls, two accessible names ("Safety cover" and "Master cutoff"), so the two-step process is audible as well as visible. Collapsing them into one control with a hidden gate would make the demo untestable by keyboard.
- Closing the set: this is the collection's argument in one component — native inputs doing the semantics, Tailwind variants doing every visual state, ten lines of JavaScript for the one rule CSS cannot enforce, and a reduced-motion path that keeps the guard legible at 100ms.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Guarded Kill Switch Under a Flip-Up Safety Cover
Source: https://codefronts.com/components/tailwind-css-toggles-switches/tailwind-guarded-kill-switch-safety-cover/
The finale: a red safety cover you must flip up before the switch beneath can be thrown, exactly like the guarded toggles on aircraft panels. Two deliberate actions, a warning strip that wakes up, and closing the cover kills the switch automatically.
## HTML
```html
<section class="ttg-47 w-full min-h-svh grid place-items-center px-5 py-14 bg-ttg47-bg font-ttg47-mono" aria-label="Guarded kill switch">
<div id="ttg-47-panel" class="relative w-[min(340px,100%)] flex flex-col gap-5 px-7 py-6 rounded-[18px] bg-linear-165 from-ttg47-panelhi to-ttg47-panello shadow-[0_28px_56px_-28px_oklch(0_0_0/0.95),inset_0_1px_0_oklch(1_0_0/0.08)] has-checked:[&_.ttg47-stripe]:animate-ttg47-pulse motion-reduce:has-checked:[&_.ttg47-stripe]:animate-none">
<span aria-hidden="true" class="ttg47-stripe h-1.5 rounded-full opacity-40 [background:repeating-linear-gradient(135deg,var(--color-ttg47-hazard)_0_10px,var(--color-ttg47-panelhi)_10px_20px)]"></span>
<span class="flex flex-col gap-0.5">
<b class="text-[14px] font-bold tracking-[0.16em] text-ttg47-ink">MASTER CUTOFF</b>
<span class="font-ttg47-sans text-[12.5px] text-ttg47-mute">Flip the guard, then throw the switch</span>
</span>
<div class="relative h-28 perspective-[420px]">
<div class="absolute inset-0 flex items-center justify-center gap-4 rounded-xl bg-ttg47-recess shadow-[inset_0_3px_10px_oklch(0_0_0/0.8)]">
<input type="checkbox" id="ttg-47-kill" role="switch" aria-label="Master cutoff" disabled class="appearance-none w-20 h-11 rounded-full bg-ttg47-trackoff relative cursor-pointer transition-[background-color,opacity] duration-300 disabled:opacity-40 disabled:cursor-not-allowed before:content-[''] before:absolute before:top-1 before:left-1 before:w-9 before:h-9 before:rounded-full before:bg-ttg47-thumb before:shadow-[0_2px_6px_oklch(0_0_0/0.6)] before:transition-transform before:duration-300 before:ease-[cubic-bezier(0.25,0.9,0.3,1.1)] checked:bg-ttg47-hazard checked:before:translate-x-9 focus-visible:outline-3 focus-visible:outline-ttg47-focus focus-visible:outline-offset-4 motion-reduce:transition-none motion-reduce:before:transition-none">
<span id="ttg-47-state" class="font-ttg47-sans text-[13px] font-bold tracking-[0.08em] text-ttg47-mute">SAFE</span>
</div>
<input type="checkbox" id="ttg-47-guard" class="peer sr-only" aria-label="Safety cover">
<label for="ttg-47-guard" class="absolute inset-0 grid place-items-center rounded-xl cursor-pointer origin-top bg-linear-to-b from-ttg47-coverhi to-ttg47-coverlo border-2 border-ttg47-coveredge shadow-[0_10px_20px_-8px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.3)] transition-transform duration-[420ms] ease-[cubic-bezier(0.35,1.25,0.5,1)] peer-checked:-rotate-x-[105deg] peer-focus-visible:outline-3 peer-focus-visible:outline-ttg47-focus peer-focus-visible:outline-offset-4 motion-reduce:duration-100">
<span class="flex flex-col items-center gap-1 text-center">
<b class="text-[12px] font-extrabold tracking-[0.2em] text-white">LIFT GUARD</b>
<span class="font-ttg47-sans text-[10.5px] tracking-[0.1em] text-white/80">Two-step arming</span>
</span>
</label>
</div>
<p id="ttg-47-live" aria-live="polite" class="font-ttg47-sans text-[12px] text-ttg47-mute">Guard closed · switch locked</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}
```
## JavaScript
```js
(() => {
const guard = document.querySelector('#ttg-47-guard');
const kill = document.querySelector('#ttg-47-kill');
const state = document.querySelector('#ttg-47-state');
const live = document.querySelector('#ttg-47-live');
if (!guard || !kill || !state || !live) return;
const report = () => {
const armed = kill.checked;
state.textContent = armed ? 'ARMED' : 'SAFE';
state.style.color = armed ? 'var(--color-ttg47-hazard)' : '';
live.textContent = !guard.checked
? 'Guard closed \u00b7 switch locked'
: (armed ? 'Cutoff ARMED \u2014 close the guard to disarm' : 'Guard open \u00b7 switch unlocked');
};
guard.addEventListener('change', () => {
kill.disabled = !guard.checked;
if (!guard.checked) kill.checked = false; // closing the cover always disarms
report();
});
kill.addEventListener('change', report);
report();
})();
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Guarded Kill Switch Under a Flip-Up Safety Cover
Source: https://codefronts.com/components/tailwind-css-toggles-switches/tailwind-guarded-kill-switch-safety-cover/
The finale: a red safety cover you must flip up before the switch beneath can be thrown, exactly like the guarded toggles on aircraft panels. Two deliberate actions, a warning strip that wakes up, and closing the cover kills the switch automatically.
## HTML
```html
<section class="ttg-47 w-full min-h-svh grid place-items-center px-5 py-14 bg-ttg47-bg font-ttg47-mono" aria-label="Guarded kill switch">
<div id="ttg-47-panel" class="relative w-[min(340px,100%)] flex flex-col gap-5 px-7 py-6 rounded-[18px] bg-linear-165 from-ttg47-panelhi to-ttg47-panello shadow-[0_28px_56px_-28px_oklch(0_0_0/0.95),inset_0_1px_0_oklch(1_0_0/0.08)] has-checked:[&_.ttg47-stripe]:animate-ttg47-pulse motion-reduce:has-checked:[&_.ttg47-stripe]:animate-none">
<span aria-hidden="true" class="ttg47-stripe h-1.5 rounded-full opacity-40 [background:repeating-linear-gradient(135deg,var(--color-ttg47-hazard)_0_10px,var(--color-ttg47-panelhi)_10px_20px)]"></span>
<span class="flex flex-col gap-0.5">
<b class="text-[14px] font-bold tracking-[0.16em] text-ttg47-ink">MASTER CUTOFF</b>
<span class="font-ttg47-sans text-[12.5px] text-ttg47-mute">Flip the guard, then throw the switch</span>
</span>
<div class="relative h-28 perspective-[420px]">
<div class="absolute inset-0 flex items-center justify-center gap-4 rounded-xl bg-ttg47-recess shadow-[inset_0_3px_10px_oklch(0_0_0/0.8)]">
<input type="checkbox" id="ttg-47-kill" role="switch" aria-label="Master cutoff" disabled class="appearance-none w-20 h-11 rounded-full bg-ttg47-trackoff relative cursor-pointer transition-[background-color,opacity] duration-300 disabled:opacity-40 disabled:cursor-not-allowed before:content-[''] before:absolute before:top-1 before:left-1 before:w-9 before:h-9 before:rounded-full before:bg-ttg47-thumb before:shadow-[0_2px_6px_oklch(0_0_0/0.6)] before:transition-transform before:duration-300 before:ease-[cubic-bezier(0.25,0.9,0.3,1.1)] checked:bg-ttg47-hazard checked:before:translate-x-9 focus-visible:outline-3 focus-visible:outline-ttg47-focus focus-visible:outline-offset-4 motion-reduce:transition-none motion-reduce:before:transition-none">
<span id="ttg-47-state" class="font-ttg47-sans text-[13px] font-bold tracking-[0.08em] text-ttg47-mute">SAFE</span>
</div>
<input type="checkbox" id="ttg-47-guard" class="peer sr-only" aria-label="Safety cover">
<label for="ttg-47-guard" class="absolute inset-0 grid place-items-center rounded-xl cursor-pointer origin-top bg-linear-to-b from-ttg47-coverhi to-ttg47-coverlo border-2 border-ttg47-coveredge shadow-[0_10px_20px_-8px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.3)] transition-transform duration-[420ms] ease-[cubic-bezier(0.35,1.25,0.5,1)] peer-checked:-rotate-x-[105deg] peer-focus-visible:outline-3 peer-focus-visible:outline-ttg47-focus peer-focus-visible:outline-offset-4 motion-reduce:duration-100">
<span class="flex flex-col items-center gap-1 text-center">
<b class="text-[12px] font-extrabold tracking-[0.2em] text-white">LIFT GUARD</b>
<span class="font-ttg47-sans text-[10.5px] tracking-[0.1em] text-white/80">Two-step arming</span>
</span>
</label>
</div>
<p id="ttg-47-live" aria-live="polite" class="font-ttg47-sans text-[12px] text-ttg47-mute">Guard closed · switch locked</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-ttg47-bg: #15171b;
--color-ttg47-bg: oklch(0.21 0.005 265);
--color-ttg47-panelhi: #33373e;
--color-ttg47-panelhi: oklch(0.33 0.007 265);
--color-ttg47-panello: #24272c;
--color-ttg47-panello: oklch(0.27 0.006 265);
--color-ttg47-recess: #17191d;
--color-ttg47-recess: oklch(0.2 0.005 265);
--color-ttg47-coverhi: #d8452f;
--color-ttg47-coverhi: oklch(0.58 0.2 28);
--color-ttg47-coverlo: #97281c;
--color-ttg47-coverlo: oklch(0.43 0.17 28);
--color-ttg47-coveredge: #f07a63;
--color-ttg47-coveredge: oklch(0.7 0.16 30);
--color-ttg47-hazard: #f0a63c;
--color-ttg47-hazard: oklch(0.78 0.15 68);
--color-ttg47-trackoff: #3a3f49;
--color-ttg47-trackoff: oklch(0.38 0.012 265);
--color-ttg47-thumb: #e7eaf0;
--color-ttg47-thumb: oklch(0.93 0.006 265);
--color-ttg47-ink: #e8ebf1;
--color-ttg47-ink: oklch(0.93 0.006 265);
--color-ttg47-mute: #9aa1ad;
--color-ttg47-mute: oklch(0.71 0.012 265);
--color-ttg47-focus: #6cb6f0;
--color-ttg47-focus: oklch(0.74 0.14 235);
--font-ttg47-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
--font-ttg47-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--animate-ttg47-pulse: ttg47-pulse 1.6s ease-in-out infinite;
}
@keyframes ttg47-pulse {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
.ttg-47 {
width: 100%;
min-height: 100svh;
}
.ttg-47 input[type="checkbox"] {
-webkit-appearance: none;
}
```
## JavaScript
```js
(() => {
const guard = document.querySelector('#ttg-47-guard');
const kill = document.querySelector('#ttg-47-kill');
const state = document.querySelector('#ttg-47-state');
const live = document.querySelector('#ttg-47-live');
if (!guard || !kill || !state || !live) return;
const report = () => {
const armed = kill.checked;
state.textContent = armed ? 'ARMED' : 'SAFE';
state.style.color = armed ? 'var(--color-ttg47-hazard)' : '';
live.textContent = !guard.checked
? 'Guard closed \u00b7 switch locked'
: (armed ? 'Cutoff ARMED \u2014 close the guard to disarm' : 'Guard open \u00b7 switch unlocked');
};
guard.addEventListener('change', () => {
kill.disabled = !guard.checked;
if (!guard.checked) kill.checked = false; // closing the cover always disarms
report();
});
kill.addEventListener('change', report);
report();
})();
```How this works
The guard is a real gate, not a decoration. While it is closed the kill switch is genuinely disabled, so it cannot be clicked, tabbed to or activated by script-free means. The cover is not hiding the control; it is holding it.
Closing the cover disarms. If the switch was thrown and you shut the guard, the switch returns to off — the physical behaviour of the hardware this imitates, and the reason the pattern is trusted for destructive actions.
Two actions, two affordances. The cover is a checkbox with its own label and its own accessible name ("Safety cover"); the kill switch is a second checkbox. Neither pretends to be the other, so a screen reader hears exactly the two-step process a sighted user sees.
Make it yours
- Change the hinge to the side with
origin-leftandrotate-y. - Auto-close the guard after N seconds of inactivity — the timer pattern from demo 30 drops straight in.
- Add a hold requirement on the inner switch by combining with demo 11.
- Recolour to yellow-black hazard striping for an industrial panel.
Gotchas — read before shipping
- Actually disable the inner control. A guard that only covers the switch visually can still be tabbed to and activated, which is worse than no guard.
- Force the inner switch off when the guard closes, or the panel can report armed while it looks safe.
- Two nested interactive controls need two distinct accessible names, or the pattern is incomprehensible without sight.
origin-topplusperspectiveon the parent, or the cover scales instead of hinging.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms and :has() (Firefox 121+); the disabled gating is plain HTML and works regardless.