17 / 36
All 36 in 36 Tailwind CSS Modals
- 01Tailwind Login / Signup Modal with Native Dialog & Starting-Style
- 02Tailwind Password Reset Modal with In-Place Success State
- 03Tailwind Age Verification Gate with :has() and Zero JavaScript
- 04Tailwind Paywall Modal with Masked Article Fade
- 05Tailwind Product Quick-View Modal with has-checked Variant Chips
- 06Tailwind Shopping Cart Slide-Over Drawer with Dialog
- 07Tailwind Timed Newsletter Promo Popup with Frequency Cap
- 08Tailwind Size Guide Overlay with Zero-JS cm/inch Toggle
- 09Tailwind Zero-JS Lightbox Gallery with the target Variant
- 10Tailwind Video Trailer Modal with Aspect-Locked Iframe
- 11Tailwind Destructive Delete Modal with Type-to-Confirm Gate
- 12Tailwind Success / Error Result Modal with Drawn SVG Icon
- 13Tailwind GDPR Cookie Consent Banner with details Disclosure
- 14Tailwind Multi-Step Onboarding Modal with data-step Variants
- 15Tailwind Filter & Sort Drawer that Becomes a Bottom Sheet
- 16Tailwind Contact Support Modal with Live Validation
- 17Tailwind Tabbed Settings Modal with Zero-JS Radio Tabs
- 18Tailwind Command Palette Modal with ⌘K and Roving Selection
- 19Tailwind Confirm Delete Modal with Corner Slide-and-Spin Entrance
- 20Tailwind Login Modal with Staggered Blur-In Content Drop
- 21Tailwind Signup Modal with 3D Origami Fan Deploy Panels
- 22Tailwind Payment Checkout Modal with 3D Paper Fold Entrance
- 23Tailwind HIPAA Patient Consent Modal with Scroll-Gated Agreement
- 24Tailwind Age Verification Modal with Clip-Path Iris Aperture
- 25Tailwind GDPR Cookie Preferences Modal with Unfolding Category Rows
- 26Tailwind Video Lightbox Modal with Chromatic Glitch Materialize
- 27Tailwind Image Gallery Lightbox with Clip-Path Diamond Reveal
- 28Tailwind Add to Cart Confirmation with SVG Liquid Morph Entrance
- 29Tailwind Product Quick View Modal with Elastic Button Morph
- 30Tailwind Newsletter Signup Modal with Depth-Layer Parallax Entrance
- 31Tailwind Exit-Intent Discount Modal with Live Countdown and Coupon Copy
- 32Tailwind Restaurant Reservation Modal with Cascading Fan Panels
- 33Tailwind Order Success Modal with CSS-Only Confetti Burst
- 34Tailwind SaaS Onboarding Welcome Modal with Cascading Blur-In
- 35Tailwind Terms of Service Modal with Letter-Slide and Consent Gate
- 36Tailwind Password Reset Modal with Enumeration-Safe Confirmation
Tailwind Tabbed Settings Modal with Zero-JS Radio Tabs
A preferences dialog with a vertical nav and three panels, switched entirely by radios: no tab controller, no aria-selected bookkeeping. group-has-[#tm-17-appear:checked]: selects both the active nav item and its panel, from the class list of each.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tm-17 w-full min-h-svh grid place-items-center bg-tm17-bg font-tm17-sans px-6 py-10">
<button type="button" data-tm17-open class="inline-flex items-center gap-2.5 min-h-11 px-6 rounded-xl text-sm font-semibold text-tm17-ink bg-tm17-btn border border-tm17-edge cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:border-tm17-acc focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2"><span aria-hidden="true">⚙</span> Settings</button>
<dialog id="tm-17-dlg" aria-labelledby="tm-17-title" class="m-auto w-[min(620px,94vw)] max-h-[90dvh] overflow-hidden p-0 border-0 rounded-[18px] text-tm17-ink bg-tm17-card shadow-[0_40px_90px_-30px_#000,0_0_0_1px_var(--color-tm17-edge)] opacity-0 scale-[0.97] transition-[opacity,translate,scale,overlay,display] duration-[260ms] transition-discrete open:opacity-100 open:scale-100 open:starting:opacity-0 open:starting:scale-[0.97] open:backdrop:bg-tm17-scrim open:backdrop:backdrop-blur-[5px] motion-reduce:transition-none">
<div data-tm17-card class="group relative grid grid-cols-[190px_1fr] min-h-[420px] max-[540px]:grid-cols-1">
<input type="radio" name="tm-17-tab" id="tm-17-account" checked class="peer/account sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-appear" class="peer/appear sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-notif" class="peer/notif sr-only">
<button type="button" data-tm17-close aria-label="Close settings" class="absolute top-2.5 right-3 z-[3] grid place-items-center size-11 rounded-lg border-0 bg-transparent text-tm17-mut text-[22px] leading-none cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:text-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2">×</button>
<nav aria-label="Settings sections" class="flex flex-col gap-1 px-3.5 py-6 bg-tm17-nav border-r border-tm17-edge max-[540px]:flex-row max-[540px]:overflow-auto max-[540px]:border-r-0 max-[540px]:border-b max-[540px]:py-3">
<h2 id="tm-17-title" class="px-3 mb-3.5 text-[13px] uppercase tracking-[0.16em] text-tm17-faint max-[540px]:hidden">Settings</h2>
<label for="tm-17-account" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-account:checked]:bg-tm17-acctint group-has-[#tm-17-account:checked]:text-white group-has-[#tm-17-account:focus-visible]:outline-2 group-has-[#tm-17-account:focus-visible]:outline-tm17-acc group-has-[#tm-17-account:focus-visible]:-outline-offset-2"><span aria-hidden="true">👤</span> Account</label>
<label for="tm-17-appear" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-appear:checked]:bg-tm17-acctint group-has-[#tm-17-appear:checked]:text-white group-has-[#tm-17-appear:focus-visible]:outline-2 group-has-[#tm-17-appear:focus-visible]:outline-tm17-acc group-has-[#tm-17-appear:focus-visible]:-outline-offset-2"><span aria-hidden="true">🎨</span> Appearance</label>
<label for="tm-17-notif" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-notif:checked]:bg-tm17-acctint group-has-[#tm-17-notif:checked]:text-white group-has-[#tm-17-notif:focus-visible]:outline-2 group-has-[#tm-17-notif:focus-visible]:outline-tm17-acc group-has-[#tm-17-notif:focus-visible]:-outline-offset-2"><span aria-hidden="true">🔔</span> Notifications</label>
</nav>
<div class="overflow-auto px-7 py-7">
<section class="hidden group-has-[#tm-17-account:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Account</h3>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-dn" class="text-[12.5px] font-semibold text-tm17-mut">Display name</label>
<input id="tm-17-dn" type="text" value="Alex Rivera" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-em" class="text-[12.5px] font-semibold text-tm17-mut">Email</label>
<input id="tm-17-em" type="email" value="alex@studio.co" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5">
<label for="tm-17-tz" class="text-[12.5px] font-semibold text-tm17-mut">Time zone</label>
<select id="tm-17-tz" class="w-full min-h-11 px-3 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi cursor-pointer transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
<option>GMT−05:00 · New York</option><option>GMT+00:00 · London</option><option>GMT+05:30 · Mumbai</option>
</select>
</div>
</section>
<section class="hidden group-has-[#tm-17-appear:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Appearance</h3>
<p class="mb-3 text-[12.5px] font-semibold text-tm17-mut">Theme</p>
<div class="flex gap-3 mb-6">
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" checked class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#15131f]"></span>Dark</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#e8e6f0]"></span>Light</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[linear-gradient(90deg,#15131f_50%,#e8e6f0_50%)]"></span>System</label>
</div>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Reduce motion</span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Compact density</span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
<section class="hidden group-has-[#tm-17-notif:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Notifications</h3>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Product updates</b><small class="text-xs text-tm17-faint">New features & releases</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Mentions & replies</b><small class="text-xs text-tm17-faint">When someone tags you</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Weekly digest</b><small class="text-xs text-tm17-faint">A Monday summary email</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Marketing</b><small class="text-xs text-tm17-faint">Occasional offers</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
</div>
</div>
</dialog>
</section><section class="tm-17 w-full min-h-svh grid place-items-center bg-tm17-bg font-tm17-sans px-6 py-10">
<button type="button" data-tm17-open class="inline-flex items-center gap-2.5 min-h-11 px-6 rounded-xl text-sm font-semibold text-tm17-ink bg-tm17-btn border border-tm17-edge cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:border-tm17-acc focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2"><span aria-hidden="true">⚙</span> Settings</button>
<dialog id="tm-17-dlg" aria-labelledby="tm-17-title" class="m-auto w-[min(620px,94vw)] max-h-[90dvh] overflow-hidden p-0 border-0 rounded-[18px] text-tm17-ink bg-tm17-card shadow-[0_40px_90px_-30px_#000,0_0_0_1px_var(--color-tm17-edge)] opacity-0 scale-[0.97] transition-[opacity,translate,scale,overlay,display] duration-[260ms] transition-discrete open:opacity-100 open:scale-100 open:starting:opacity-0 open:starting:scale-[0.97] open:backdrop:bg-tm17-scrim open:backdrop:backdrop-blur-[5px] motion-reduce:transition-none">
<div data-tm17-card class="group relative grid grid-cols-[190px_1fr] min-h-[420px] max-[540px]:grid-cols-1">
<input type="radio" name="tm-17-tab" id="tm-17-account" checked class="peer/account sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-appear" class="peer/appear sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-notif" class="peer/notif sr-only">
<button type="button" data-tm17-close aria-label="Close settings" class="absolute top-2.5 right-3 z-[3] grid place-items-center size-11 rounded-lg border-0 bg-transparent text-tm17-mut text-[22px] leading-none cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:text-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2">×</button>
<nav aria-label="Settings sections" class="flex flex-col gap-1 px-3.5 py-6 bg-tm17-nav border-r border-tm17-edge max-[540px]:flex-row max-[540px]:overflow-auto max-[540px]:border-r-0 max-[540px]:border-b max-[540px]:py-3">
<h2 id="tm-17-title" class="px-3 mb-3.5 text-[13px] uppercase tracking-[0.16em] text-tm17-faint max-[540px]:hidden">Settings</h2>
<label for="tm-17-account" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-account:checked]:bg-tm17-acctint group-has-[#tm-17-account:checked]:text-white group-has-[#tm-17-account:focus-visible]:outline-2 group-has-[#tm-17-account:focus-visible]:outline-tm17-acc group-has-[#tm-17-account:focus-visible]:-outline-offset-2"><span aria-hidden="true">👤</span> Account</label>
<label for="tm-17-appear" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-appear:checked]:bg-tm17-acctint group-has-[#tm-17-appear:checked]:text-white group-has-[#tm-17-appear:focus-visible]:outline-2 group-has-[#tm-17-appear:focus-visible]:outline-tm17-acc group-has-[#tm-17-appear:focus-visible]:-outline-offset-2"><span aria-hidden="true">🎨</span> Appearance</label>
<label for="tm-17-notif" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-notif:checked]:bg-tm17-acctint group-has-[#tm-17-notif:checked]:text-white group-has-[#tm-17-notif:focus-visible]:outline-2 group-has-[#tm-17-notif:focus-visible]:outline-tm17-acc group-has-[#tm-17-notif:focus-visible]:-outline-offset-2"><span aria-hidden="true">🔔</span> Notifications</label>
</nav>
<div class="overflow-auto px-7 py-7">
<section class="hidden group-has-[#tm-17-account:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Account</h3>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-dn" class="text-[12.5px] font-semibold text-tm17-mut">Display name</label>
<input id="tm-17-dn" type="text" value="Alex Rivera" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-em" class="text-[12.5px] font-semibold text-tm17-mut">Email</label>
<input id="tm-17-em" type="email" value="alex@studio.co" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5">
<label for="tm-17-tz" class="text-[12.5px] font-semibold text-tm17-mut">Time zone</label>
<select id="tm-17-tz" class="w-full min-h-11 px-3 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi cursor-pointer transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
<option>GMT−05:00 · New York</option><option>GMT+00:00 · London</option><option>GMT+05:30 · Mumbai</option>
</select>
</div>
</section>
<section class="hidden group-has-[#tm-17-appear:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Appearance</h3>
<p class="mb-3 text-[12.5px] font-semibold text-tm17-mut">Theme</p>
<div class="flex gap-3 mb-6">
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" checked class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#15131f]"></span>Dark</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#e8e6f0]"></span>Light</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[linear-gradient(90deg,#15131f_50%,#e8e6f0_50%)]"></span>System</label>
</div>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Reduce motion</span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Compact density</span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
<section class="hidden group-has-[#tm-17-notif:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Notifications</h3>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Product updates</b><small class="text-xs text-tm17-faint">New features & releases</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Mentions & replies</b><small class="text-xs text-tm17-faint">When someone tags you</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Weekly digest</b><small class="text-xs text-tm17-faint">A Monday summary email</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Marketing</b><small class="text-xs text-tm17-faint">Occasional offers</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
</div>
</div>
</dialog>
</section>@import "tailwindcss";
@theme {
--color-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}@import "tailwindcss";
@theme {
--color-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}(function () {
var root = document.querySelector('.tm-17');
var dlg = root.querySelector('#tm-17-dlg');
var card = root.querySelector('[data-tm17-card]');
root.querySelector('[data-tm17-open]').addEventListener('click', function () { dlg.showModal(); });
root.querySelector('[data-tm17-close]').addEventListener('click', function () { dlg.close(); });
dlg.addEventListener('click', function (e) {
var r = card.getBoundingClientRect();
if (e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom) dlg.close();
});
})();(function () {
var root = document.querySelector('.tm-17');
var dlg = root.querySelector('#tm-17-dlg');
var card = root.querySelector('[data-tm17-card]');
root.querySelector('[data-tm17-open]').addEventListener('click', function () { dlg.showModal(); });
root.querySelector('[data-tm17-close]').addEventListener('click', function () { dlg.close(); });
dlg.addEventListener('click', function (e) {
var r = card.getBoundingClientRect();
if (e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom) dlg.close();
});
})();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-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}@import "tailwindcss";
@theme {
--color-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}<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=Space+Grotesk:wght@400;500;600;700&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=Space+Grotesk:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Six sibling-combinator selectors (three for the nav, three for the panels) become
group-has-[#id:checked]:variants on the labels and the panels. The relational form is required, not stylistic: the radios sit at card level while the labels live inside<nav>, sopeer-*— which only reaches following siblings — silently never matches. - The toggle switch appears four times with identical utilities, which is the honest cost of a component that has no component. In a template this is a partial; in flat HTML it is repetition.
- UI change from the CSS original: nav items, inputs and the close button all reach 44px, the theme cards use
has-checked:with border AND fill (colour alone was the only selected signal before), and the mobile nav scrolls horizontally withwhitespace-nowrapinstead of wrapping into two cramped rows.
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 Tabbed Settings Modal with Zero-JS Radio Tabs
Source: https://codefronts.com/components/tailwind-css-modals/tailwind-tabbed-settings-modal-zero-js-radio-tabs/
A preferences dialog with a vertical nav and three panels, switched entirely by radios: no tab controller, no aria-selected bookkeeping. group-has-[#tm-17-appear:checked]: selects both the active nav item and its panel, from the class list of each.
## HTML
```html
<section class="tm-17 w-full min-h-svh grid place-items-center bg-tm17-bg font-tm17-sans px-6 py-10">
<button type="button" data-tm17-open class="inline-flex items-center gap-2.5 min-h-11 px-6 rounded-xl text-sm font-semibold text-tm17-ink bg-tm17-btn border border-tm17-edge cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:border-tm17-acc focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2"><span aria-hidden="true">⚙</span> Settings</button>
<dialog id="tm-17-dlg" aria-labelledby="tm-17-title" class="m-auto w-[min(620px,94vw)] max-h-[90dvh] overflow-hidden p-0 border-0 rounded-[18px] text-tm17-ink bg-tm17-card shadow-[0_40px_90px_-30px_#000,0_0_0_1px_var(--color-tm17-edge)] opacity-0 scale-[0.97] transition-[opacity,translate,scale,overlay,display] duration-[260ms] transition-discrete open:opacity-100 open:scale-100 open:starting:opacity-0 open:starting:scale-[0.97] open:backdrop:bg-tm17-scrim open:backdrop:backdrop-blur-[5px] motion-reduce:transition-none">
<div data-tm17-card class="group relative grid grid-cols-[190px_1fr] min-h-[420px] max-[540px]:grid-cols-1">
<input type="radio" name="tm-17-tab" id="tm-17-account" checked class="peer/account sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-appear" class="peer/appear sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-notif" class="peer/notif sr-only">
<button type="button" data-tm17-close aria-label="Close settings" class="absolute top-2.5 right-3 z-[3] grid place-items-center size-11 rounded-lg border-0 bg-transparent text-tm17-mut text-[22px] leading-none cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:text-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2">×</button>
<nav aria-label="Settings sections" class="flex flex-col gap-1 px-3.5 py-6 bg-tm17-nav border-r border-tm17-edge max-[540px]:flex-row max-[540px]:overflow-auto max-[540px]:border-r-0 max-[540px]:border-b max-[540px]:py-3">
<h2 id="tm-17-title" class="px-3 mb-3.5 text-[13px] uppercase tracking-[0.16em] text-tm17-faint max-[540px]:hidden">Settings</h2>
<label for="tm-17-account" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-account:checked]:bg-tm17-acctint group-has-[#tm-17-account:checked]:text-white group-has-[#tm-17-account:focus-visible]:outline-2 group-has-[#tm-17-account:focus-visible]:outline-tm17-acc group-has-[#tm-17-account:focus-visible]:-outline-offset-2"><span aria-hidden="true">👤</span> Account</label>
<label for="tm-17-appear" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-appear:checked]:bg-tm17-acctint group-has-[#tm-17-appear:checked]:text-white group-has-[#tm-17-appear:focus-visible]:outline-2 group-has-[#tm-17-appear:focus-visible]:outline-tm17-acc group-has-[#tm-17-appear:focus-visible]:-outline-offset-2"><span aria-hidden="true">🎨</span> Appearance</label>
<label for="tm-17-notif" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-notif:checked]:bg-tm17-acctint group-has-[#tm-17-notif:checked]:text-white group-has-[#tm-17-notif:focus-visible]:outline-2 group-has-[#tm-17-notif:focus-visible]:outline-tm17-acc group-has-[#tm-17-notif:focus-visible]:-outline-offset-2"><span aria-hidden="true">🔔</span> Notifications</label>
</nav>
<div class="overflow-auto px-7 py-7">
<section class="hidden group-has-[#tm-17-account:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Account</h3>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-dn" class="text-[12.5px] font-semibold text-tm17-mut">Display name</label>
<input id="tm-17-dn" type="text" value="Alex Rivera" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-em" class="text-[12.5px] font-semibold text-tm17-mut">Email</label>
<input id="tm-17-em" type="email" value="alex@studio.co" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5">
<label for="tm-17-tz" class="text-[12.5px] font-semibold text-tm17-mut">Time zone</label>
<select id="tm-17-tz" class="w-full min-h-11 px-3 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi cursor-pointer transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
<option>GMT−05:00 · New York</option><option>GMT+00:00 · London</option><option>GMT+05:30 · Mumbai</option>
</select>
</div>
</section>
<section class="hidden group-has-[#tm-17-appear:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Appearance</h3>
<p class="mb-3 text-[12.5px] font-semibold text-tm17-mut">Theme</p>
<div class="flex gap-3 mb-6">
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" checked class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#15131f]"></span>Dark</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#e8e6f0]"></span>Light</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[linear-gradient(90deg,#15131f_50%,#e8e6f0_50%)]"></span>System</label>
</div>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Reduce motion</span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Compact density</span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
<section class="hidden group-has-[#tm-17-notif:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Notifications</h3>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Product updates</b><small class="text-xs text-tm17-faint">New features & releases</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Mentions & replies</b><small class="text-xs text-tm17-faint">When someone tags you</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Weekly digest</b><small class="text-xs text-tm17-faint">A Monday summary email</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Marketing</b><small class="text-xs text-tm17-faint">Occasional offers</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
</div>
</div>
</dialog>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}
```
## JavaScript
```js
(function () {
var root = document.querySelector('.tm-17');
var dlg = root.querySelector('#tm-17-dlg');
var card = root.querySelector('[data-tm17-card]');
root.querySelector('[data-tm17-open]').addEventListener('click', function () { dlg.showModal(); });
root.querySelector('[data-tm17-close]').addEventListener('click', function () { dlg.close(); });
dlg.addEventListener('click', function (e) {
var r = card.getBoundingClientRect();
if (e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom) dlg.close();
});
})();
```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 Tabbed Settings Modal with Zero-JS Radio Tabs
Source: https://codefronts.com/components/tailwind-css-modals/tailwind-tabbed-settings-modal-zero-js-radio-tabs/
A preferences dialog with a vertical nav and three panels, switched entirely by radios: no tab controller, no aria-selected bookkeeping. group-has-[#tm-17-appear:checked]: selects both the active nav item and its panel, from the class list of each.
## HTML
```html
<section class="tm-17 w-full min-h-svh grid place-items-center bg-tm17-bg font-tm17-sans px-6 py-10">
<button type="button" data-tm17-open class="inline-flex items-center gap-2.5 min-h-11 px-6 rounded-xl text-sm font-semibold text-tm17-ink bg-tm17-btn border border-tm17-edge cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:border-tm17-acc focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2"><span aria-hidden="true">⚙</span> Settings</button>
<dialog id="tm-17-dlg" aria-labelledby="tm-17-title" class="m-auto w-[min(620px,94vw)] max-h-[90dvh] overflow-hidden p-0 border-0 rounded-[18px] text-tm17-ink bg-tm17-card shadow-[0_40px_90px_-30px_#000,0_0_0_1px_var(--color-tm17-edge)] opacity-0 scale-[0.97] transition-[opacity,translate,scale,overlay,display] duration-[260ms] transition-discrete open:opacity-100 open:scale-100 open:starting:opacity-0 open:starting:scale-[0.97] open:backdrop:bg-tm17-scrim open:backdrop:backdrop-blur-[5px] motion-reduce:transition-none">
<div data-tm17-card class="group relative grid grid-cols-[190px_1fr] min-h-[420px] max-[540px]:grid-cols-1">
<input type="radio" name="tm-17-tab" id="tm-17-account" checked class="peer/account sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-appear" class="peer/appear sr-only">
<input type="radio" name="tm-17-tab" id="tm-17-notif" class="peer/notif sr-only">
<button type="button" data-tm17-close aria-label="Close settings" class="absolute top-2.5 right-3 z-[3] grid place-items-center size-11 rounded-lg border-0 bg-transparent text-tm17-mut text-[22px] leading-none cursor-pointer transition-colors duration-200 hover:bg-tm17-btnhover hover:text-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2">×</button>
<nav aria-label="Settings sections" class="flex flex-col gap-1 px-3.5 py-6 bg-tm17-nav border-r border-tm17-edge max-[540px]:flex-row max-[540px]:overflow-auto max-[540px]:border-r-0 max-[540px]:border-b max-[540px]:py-3">
<h2 id="tm-17-title" class="px-3 mb-3.5 text-[13px] uppercase tracking-[0.16em] text-tm17-faint max-[540px]:hidden">Settings</h2>
<label for="tm-17-account" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-account:checked]:bg-tm17-acctint group-has-[#tm-17-account:checked]:text-white group-has-[#tm-17-account:focus-visible]:outline-2 group-has-[#tm-17-account:focus-visible]:outline-tm17-acc group-has-[#tm-17-account:focus-visible]:-outline-offset-2"><span aria-hidden="true">👤</span> Account</label>
<label for="tm-17-appear" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-appear:checked]:bg-tm17-acctint group-has-[#tm-17-appear:checked]:text-white group-has-[#tm-17-appear:focus-visible]:outline-2 group-has-[#tm-17-appear:focus-visible]:outline-tm17-acc group-has-[#tm-17-appear:focus-visible]:-outline-offset-2"><span aria-hidden="true">🎨</span> Appearance</label>
<label for="tm-17-notif" class="flex items-center gap-2.5 min-h-11 px-3 rounded-[9px] text-sm font-semibold text-tm17-mut cursor-pointer whitespace-nowrap transition-colors duration-200 hover:bg-tm17-btn hover:text-tm17-hi group-has-[#tm-17-notif:checked]:bg-tm17-acctint group-has-[#tm-17-notif:checked]:text-white group-has-[#tm-17-notif:focus-visible]:outline-2 group-has-[#tm-17-notif:focus-visible]:outline-tm17-acc group-has-[#tm-17-notif:focus-visible]:-outline-offset-2"><span aria-hidden="true">🔔</span> Notifications</label>
</nav>
<div class="overflow-auto px-7 py-7">
<section class="hidden group-has-[#tm-17-account:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Account</h3>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-dn" class="text-[12.5px] font-semibold text-tm17-mut">Display name</label>
<input id="tm-17-dn" type="text" value="Alex Rivera" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5 mb-4">
<label for="tm-17-em" class="text-[12.5px] font-semibold text-tm17-mut">Email</label>
<input id="tm-17-em" type="email" value="alex@studio.co" class="w-full min-h-11 px-3.5 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
</div>
<div class="flex flex-col gap-1.5">
<label for="tm-17-tz" class="text-[12.5px] font-semibold text-tm17-mut">Time zone</label>
<select id="tm-17-tz" class="w-full min-h-11 px-3 rounded-[10px] border border-tm17-edge bg-tm17-well text-sm text-tm17-hi cursor-pointer transition-[border-color,box-shadow] duration-200 focus:outline-none focus:border-tm17-acc focus:shadow-[0_0_0_3px_var(--color-tm17-ring)]">
<option>GMT−05:00 · New York</option><option>GMT+00:00 · London</option><option>GMT+05:30 · Mumbai</option>
</select>
</div>
</section>
<section class="hidden group-has-[#tm-17-appear:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Appearance</h3>
<p class="mb-3 text-[12.5px] font-semibold text-tm17-mut">Theme</p>
<div class="flex gap-3 mb-6">
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" checked class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#15131f]"></span>Dark</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[#e8e6f0]"></span>Light</label>
<label class="relative flex-1 flex flex-col items-center gap-2 px-2 py-3.5 rounded-xl border border-tm17-edge bg-tm17-well text-[13px] font-semibold text-tm17-mut cursor-pointer transition-colors duration-200 has-checked:border-tm17-acc has-checked:text-white has-checked:bg-tm17-acctint has-focus-visible:outline-2 has-focus-visible:outline-tm17-acc has-focus-visible:outline-offset-2"><input type="radio" name="tm-17-th" class="sr-only"><span class="w-full h-8 rounded-lg border border-tm17-swedge bg-[linear-gradient(90deg,#15131f_50%,#e8e6f0_50%)]"></span>System</label>
</div>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Reduce motion</span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="text-sm text-tm17-ink">Compact density</span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
<section class="hidden group-has-[#tm-17-notif:checked]:block animate-tm17-fade motion-reduce:animate-none">
<h3 class="mb-5 text-lg font-bold text-tm17-hi">Notifications</h3>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Product updates</b><small class="text-xs text-tm17-faint">New features & releases</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Mentions & replies</b><small class="text-xs text-tm17-faint">When someone tags you</small></span>
<input type="checkbox" checked class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Weekly digest</b><small class="text-xs text-tm17-faint">A Monday summary email</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
<label class="flex items-center justify-between gap-4 py-3.5 border-t border-tm17-edgesoft cursor-pointer">
<span class="flex flex-col gap-0.5"><b class="text-sm font-semibold text-tm17-ink">Marketing</b><small class="text-xs text-tm17-faint">Occasional offers</small></span>
<input type="checkbox" class="shrink-0 relative w-11 h-6 appearance-none rounded-full bg-tm17-off cursor-pointer transition-colors duration-200 checked:bg-tm17-acc before:content-[''] before:absolute before:top-[3px] before:left-[3px] before:size-[18px] before:rounded-full before:bg-tm17-knob before:transition-transform before:duration-200 checked:before:translate-x-5 checked:before:bg-white focus-visible:outline-2 focus-visible:outline-tm17-acc focus-visible:outline-offset-2 motion-reduce:before:transition-none">
</label>
</section>
</div>
</div>
</dialog>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tm17-bg: #08070b;
--color-tm17-bg: oklch(0.14 0.012 290);
--color-tm17-card: #14121e;
--color-tm17-card: oklch(0.2 0.02 290);
--color-tm17-nav: #100e1a;
--color-tm17-nav: oklch(0.18 0.02 290);
--color-tm17-well: #0d0b16;
--color-tm17-well: oklch(0.16 0.018 290);
--color-tm17-btn: #191627;
--color-tm17-btn: oklch(0.22 0.025 290);
--color-tm17-btnhover: #221d33;
--color-tm17-btnhover: oklch(0.26 0.032 290);
--color-tm17-edge: #2c2842;
--color-tm17-edge: oklch(0.3 0.03 290);
--color-tm17-edgesoft: #211d33;
--color-tm17-edgesoft: oklch(0.25 0.025 290);
--color-tm17-swedge: #3a3556;
--color-tm17-swedge: oklch(0.36 0.04 290);
--color-tm17-off: #2c2842;
--color-tm17-off: oklch(0.3 0.03 290);
--color-tm17-knob: #9a94b8;
--color-tm17-knob: oklch(0.68 0.03 290);
--color-tm17-hi: #f2eefb;
--color-tm17-hi: oklch(0.95 0.01 290);
--color-tm17-ink: #ddd9ec;
--color-tm17-ink: oklch(0.89 0.018 290);
--color-tm17-mut: #aba5c6;
--color-tm17-mut: oklch(0.74 0.03 290);
--color-tm17-faint: #8d87ab;
--color-tm17-faint: oklch(0.63 0.035 290);
--color-tm17-acc: #a78bfa;
--color-tm17-acc: oklch(0.74 0.15 292);
--color-tm17-acctint: #34285c;
--color-tm17-acctint: oklch(0.34 0.09 292);
--color-tm17-ring: #a78bfa3d;
--color-tm17-ring: oklch(0.74 0.15 292 / 0.24);
--color-tm17-scrim: #060509a3;
--color-tm17-scrim: oklch(0.12 0.01 290 / 0.64);
--font-tm17-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tm17-fade: tm17-fade .25s ease;
}
.tm-17 {
width: 100%;
}
@keyframes tm17-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
#tm-17-dlg::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
transition: background .3s, backdrop-filter .3s, overlay .3s allow-discrete, display .3s allow-discrete;
}
@starting-style {
#tm-17-dlg[open]::backdrop {
background: oklch(0.12 0.01 290 / 0);
backdrop-filter: blur(0px);
}
}
```
## JavaScript
```js
(function () {
var root = document.querySelector('.tm-17');
var dlg = root.querySelector('#tm-17-dlg');
var card = root.querySelector('[data-tm17-card]');
root.querySelector('[data-tm17-open]').addEventListener('click', function () { dlg.showModal(); });
root.querySelector('[data-tm17-close]').addEventListener('click', function () { dlg.close(); });
dlg.addEventListener('click', function (e) {
var r = card.getBoundingClientRect();
if (e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom) dlg.close();
});
})();
```How this works
Tabs are radios, so the browser owns the state. Arrow keys move between them, only one can be active, and the selected tab survives a form reset — behaviour a JS tab widget has to reimplement and usually half-implements. The three panels each carry one group-has-[…]:block and are otherwise hidden.
The nav reads the radio two ways. peer-checked/… tints the label; peer-focus-visible/… rings it. The radios themselves are sr-only — present, focusable, announced — rather than hidden.
Panels share a min-height. min-h-[420px] on the card stops the dialog resizing as you move between a three-field panel and a four-toggle one, which is the detail that makes a tabbed modal feel solid.
Make it yours
- Add a tab: one radio, one label, one panel, each with the next id in the
has-variants. - Wire the theme radios to a
data-themeattribute on the root for a live preview. - Decide between instant-save and an explicit Save row, and make the choice visible — a settings panel that silently discards on close is the worst of both.
Gotchas — read before shipping
- Keep the driving radios
sr-only, neverhidden— the entire keyboard story depends on them being focusable. - Give panels a shared minimum height, or the dialog jumps as the user switches tabs and the close button moves under their cursor.
- A toggle switch must stay a real checkbox. Custom div-switches lose Space, lose the announced checked state, and lose form submission.
group-has-[#id:checked]:is verbose but correct here: three independent gates under one group, exactly the case where a barehas-checked:matches all of them at once.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ · 117+ anim | 16.4+ · 17.5+ anim | 128+ · 129+ anim | 111+ · 117+ anim |
:has() gates the tab switching (Firefox 121); the dialog, radios and toggles work everywhere.