47 Tailwind CSS Toggles & Switches

38 Pure Tailwind9 Tailwind + JSPublished

47 Tailwind CSS toggles & switches for dark-mode theme switchers, settings and permission rows, SaaS billing toggles, and destructive-action guards — spanning iOS-style pill and Material 3 switches, neumorphic, glassmorphism, neon and brutalist styles, gooey and squash-and-stretch physics, three-position and tri-state selectors, rotary knobs, and hold-to-confirm kill switches. Scoped under .ttg-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.

Related47 CSS Toggles & Switches30 Tailwind CSS Login Forms20 Tailwind CSS Custom Selects17 Tailwind CSS Range Sliders29 Tailwind CSS Checkboxes24 Tailwind CSS Radio Buttons

Premium upgradePartner: Untitled UI

Affiliate link

Building a whole Tailwind app, not just this component?

You just browsed 47 Tailwind toggles switches. Untitled UI Pro unlocks 5,000+ components and sections and 250+ page examples for React, styled with Tailwind CSS v4. One licence is a one-time $349 with lifetime updates; teams start at $999.

Get Untitled UI Pro

Untitled UI React. We may earn a commission, at no extra cost to you.

01. Tailwind iOS-Style Toggle Switch with appearance-none (opens in a new tab)

Published

Pure Tailwind
The most searched toggle on earth, ported: appearance-none turns the checkbox itself into the 52×32 track, a before: thumb glides across on checked:before:translate-x-5, and active:before:w-8 reproduces the native iOS squash. The port's win is that the resting, on, pressed and reduced-motion states all sit in one class list on the input.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

25. Tailwind Squash-and-Stretch Pebble Toggle (opens in a new tab)

Published

Pure Tailwind
A river pebble instead of a circle: the asymmetric blob squashes as it launches, stretches mid-flight and wobbles back into shape on landing. Two --animate-* tokens — one for checking, one for unchecking — because a transition cannot sequence anticipate → stretch → settle.

29. Tailwind Radial VU Meter Mute Toggle (opens in a new tab)

Published

Pure Tailwind
The waveform idea rebuilt as studio hardware: a radial VU meter whose needle sweeps while audio is live and drops to the peg when muted, over a masked conic arc that runs green through amber to red. Same job as demo 09, a completely different read.
FAQ

Frequently asked questions

How does the iOS-style toggle in demo 01 turn a plain checkbox into a switch?
The trick is appearance-none on the <input type="checkbox"> itself, which strips the native tick box so you can size and paint the element as the whole track. In demo 01 the input becomes a 52px pill; a pseudo-element or a sibling <span> acts as the thumb, and the checked state slides it with peer-checked:translate-x-full when the label wraps a peer input, or with checked: variants directly on the input. Because it is still a real checkbox, it submits with a form, toggles on Space, and exposes a checked state to assistive tech for free. Two things to keep: give it a paired <label> so the whole pill is clickable, and set an explicit width and height — an appearance-none checkbox collapses to near-zero intrinsic size, so a missing dimension is why your track renders as a sliver.
Why does my :has() status badge in a permission group never update?
Demo 13 and demo 33 read their own children with :has() — the card header flips a badge when has-[:checked] or the more precise has-[input:checked] matches a descendant. Three things break it. First, :has() looks at the DOM subtree, so the toggles must actually be inside the element carrying the variant, not siblings of it. Second, the inputs must be real form controls that hold a :checked state; a <div> painted to look checked will never match. Third, a fully custom appearance-none checkbox still reports :checked, but if you hid it with display:none some engines drop it from matching — use sr-only or appearance-none with zero opacity instead. For the tri-state master in demo 33 you also need the :indeterminate state, set in script via the element's indeterminate property since no attribute or utility expresses it.
What is the accessible way to build these when the control is a button, not a checkbox?
Demo 27 is the reference: a <button type="button"> with role="switch" and aria-checked toggled between true and false in the click handler. Use this shape when the toggle acts immediately on state rather than submitting inside a form. The rules: the button needs an accessible name — visible text or aria-label — and it must respond to both Enter and Space, which a real button does natively (a <div> with a click listener does not). Never animate away the focus ring; keep a visible focus-visible: outline. The demo also ships forced-colors support so the track and thumb stay distinguishable in Windows high-contrast mode, where your background colours are discarded — draw the on/off distinction with a border or the thumb position, never colour alone, or the switch becomes a single flat block that reads identically in both states.
How does the gooey morphing switch in demo 04 make the thumb neck and snap?
It is the classic gooey filter: an inline <svg> defines a filter with feGaussianBlur to soften edges into a haze, then feColorMatrix ramps the alpha channel hard so anything below a threshold vanishes and anything above snaps to solid. Applied to a container holding the track blob and the moving thumb, two shapes that overlap during the slide fuse into one surface that necks and pinches — the liquid look. The gotcha is that the filter lives in real SVG markup you must keep in the DOM; a Tailwind filter utility cannot express this chain, so the element references it via filter:url(#id). Two failure modes: the filter needs a solid backdrop because blur over a transparent area bleeds a grey fringe, and the blur is genuinely expensive, so keep the filtered subtree tiny. If you only need a bounce, demo 05's spring easing is far cheaper than paying for a per-frame blur.
The conic border light in demo 37 won't animate — the gradient just sits there. Why?
A conic gradient's angle is not animatable on its own; the browser has no way to interpolate a raw <angle> buried in a background string. Demo 37 fixes this by registering a custom property as a real typed angle with @property, giving it syntax:"<angle>", an initial value and inherits:false. Once the property is typed, the keyframe can transition it from 0deg to 360deg and the conic gradient reads that variable, so the light appears to sweep. The usual bug is declaring the variable with a plain --angle:0deg — that is a string as far as animation is concerned and stays frozen. It must go through @property. Same mechanism drives the conic countdown ring in demo 10. Note @property is a fairly recent feature; behind it, gate the motion with @supports or accept a static border on older engines rather than a broken one.
How do the SaaS pricing toggle (demo 07) and three-position selector (demo 41) track state without JavaScript?
Both use grouped <input type="radio"> controls hidden with sr-only, wrapped in <label> elements so clicking a word checks the matching radio. The sliding highlight is a single absolutely-positioned pill whose translate-x is driven by which radio is :checked, using sibling combinators or peer-checked: variants — Monthly sits at 0, Annually slides one segment over. Demo 41's Off / Auto / On is the same idea at thirds, the thumb travelling to 33% and 66%. Radios matter because they enforce mutual exclusion for free: one name, one checked at a time. The common mistake is forgetting to share a single name across the group, which lets two segments check at once and leaves the highlight stranded between them. Keep the labels focusable and arrow-key navigable — a native radio group already moves selection with the arrow keys, so don't intercept them.
The frosted glass toggle in demo 21 shows no blur — it's just a flat translucent pill. What's wrong?
backdrop-blur samples whatever is painted behind the element, so it only shows an effect when there is content underneath to blur. Demo 21 floats the switch over a vivid scene; drop the same pill on a flat solid page and there is nothing to sample, so you see a plain semi-transparent shape. Three requirements: the element needs a translucent background — a fully opaque fill hides the blurred layer entirely — plus backdrop-blur-[14px] and, in the demo, backdrop-saturate-150 to deepen the colours it pulls through. The classic bug is an ancestor with overflow:hidden and a transform or filter, which establishes a new stacking context and clips the backdrop source, killing the blur. Also note backdrop-filter is a compositing cost on every paint, so reserve it for a real glass surface over imagery, not a switch sitting on a solid card where a normal translucent fill looks identical.
When should I not use the flashier toggles like the split-flap, cube, or gooey ones?
Treat demos 12, 40, 04, 08 and their kin as feature moments, not utility controls. A 3D split-flap or rotateY cube toggle is delightful once on a landing page or a settings hero, but a form with fifteen of them is exhausting and slow — the perspective transforms and, for the gooey filter, the per-frame blur all cost paint work. For a dense settings list, ship the plain appearance-none switch from demo 01 or the iOS grouped rows from demo 23. Two hard limits regardless of style: every continuous or bouncy animation must collapse under motion-reduce: variants so a user who set reduce motion gets an instant state change, not a spin; and each control still needs a real checkbox or a role="switch" button underneath, keyboard-operable and labelled. If a demo's charm depends entirely on a hover or a long animation to reveal its state, it fails on touch and for reduced-motion users — pick a quieter one there.

Related collections

15 CSS 3D Tilt Hover Cards preview

15 CSS 3D Tilt Hover Cards

15 mouse-aware 3D tilt hover cards — e-commerce product spotlight, glassmorphism parallax team card, interactive pricing tier, holographic NFT collectible, pop-out mascot, dark tech grid with border glow, media player album art, blog article preview, cyberpunk neon glow, dashboard KPI widget, minimalist real estate, flip-to-back tilt, mobile app showcase, course learning card, and a Pure CSS touch-friendly tilt. Vanilla JS writes --rx/--ry/--mx/--my; all rendering stays in CSS on the GPU.

24 CSS Animated Cards preview

24 CSS Animated Cards

24 hand-coded CSS animated card patterns organised by what triggers the motion, not by card style. Scroll and entrance triggers: staggered grid reveals, @starting-style mount-in, scroll-driven scale and fade on animation-timeline: view(), View Transitions API card-to-detail morphs, blur-to-sharp lazy image loading, and FLIP re-layout when a filter changes. State-change triggers: add-to-cart success morph, like and save particle burst, expand and collapse to intrinsic height with calc-size(), swipe-to-dismiss on Pointer Events, and skeleton-to-loaded crossfade. Data-driven triggers: count-up KPI metrics, SVG sparkline draw-on-enter, and progress ring fill on load. Ambient idle loops: breathing glow, floating drift, animated gradient mesh backgrounds, conic rotating borders, auto-cycling testimonial decks, and live status pulses. Plus four hover patterns where the effect is the topic itself: cursor spotlight, holographic foil glare, corner ribbon slide, and horizontal accordion expand. Every card is scoped under a .ac-NN prefix for no-collision pasting, guards prefers-reduced-motion, animates compositor-only properties, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

22 CSS Avatars preview

22 CSS Avatars

22 hand-coded CSS avatars for chat apps, team dashboards, comment threads, account menus, and social profiles. Covers circular and squircle shapes, gradient and conic story rings, hexagon clip-path crops, online status dots, notification count badges, verified checkmarks, stacked facepiles with plus-N overflow, initials fallbacks for users without photos, broken-image recovery, avatar pickers, and a size scale system where the ring, badge, and status dot all scale from a single custom property.

Search CodeFronts

Loading…