Create beautiful, customizable toggle switches using Tailwind CSS
Click the toggle to test
OFF
This tool builds accessible toggle switches using Tailwind's utility-first approach. Each switch consists of two main elements:
.bg-* background track with state colors.transition-transform animated knob/thumbCommon use cases: feature toggles, dark mode switches, settings panels, and form controls.
For production use, enhance the generated code with these accessibility improvements:
<!-- Add ARIA attributes for screen readers -->
<button id="toggle"
role="switch"
aria-checked="false"
aria-labelledby="toggle-label"
class="w-10 h-6 bg-gray-200 rounded-full">
<span class="sr-only">Dark mode</span>
</button>
<span id="toggle-label" class="sr-only">Toggle dark mode</span>
role="switch" and aria-checkedsr-only labels for screen readersfocus:outline-none focus:ring-2 focus:ring-blue-500Tailwind's variant system lets you extend the toggle for different states:
<!-- Example: Adding responsive and state variants -->
<div class="w-10 h-6 bg-gray-200 rounded-full
sm:w-12 sm:h-7 <!-- Responsive sizing -->
hover:bg-gray-300 <!-- Hover state -->
focus:bg-gray-400 <!-- Focus state -->
active:bg-gray-500 <!-- Active/pressed state -->
disabled:opacity-50 <!-- Disabled state -->
transition-all duration-200">
</div>
Pro tip: Use transition-all instead of transition-transform to animate background color changes too.
The generated JavaScript is framework-agnostic. Here's how to adapt it:
import { useState } from 'react';
function ToggleSwitch({ initialOn = false }) {
const [isOn, setIsOn] = useState(initialOn);
return (
<button
onClick={() => setIsOn(!isOn)}
className={`w-10 h-6 rounded-full cursor-pointer transition-all duration-200 ${isOn ? 'bg-green-500' : 'bg-gray-200'}`}
role="switch"
aria-checked={isOn}
>
<div className={`absolute w-4 h-4 bg-white rounded-full transition-transform duration-200 ${isOn ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
);
}
<template>
<button
@click="toggle"
:class="['w-10 h-6 rounded-full cursor-pointer transition-all duration-200', isOn ? 'bg-green-500' : 'bg-gray-200']"
role="switch"
:aria-checked="isOn"
>
<div :class="['absolute w-4 h-4 bg-white rounded-full transition-transform duration-200', isOn ? 'translate-x-6' : 'translate-x-1']" />
</button>
</template>
<script setup>
import { ref } from 'vue';
const isOn = ref(false);
const toggle = () => isOn.value = !isOn.value;
</script>
Match your project's design system by customizing these Tailwind aspects:
module.exports = {
theme: {
extend: {
colors: {
'toggle-on': '#10b981',
'toggle-off': '#e5e7eb',
'knob': '#ffffff'
}
}
}
}
// Consistent sizing across your app
module.exports = {
theme: {
extend: {
spacing: {
'toggle-sm': '1rem',
'toggle-md': '1.5rem',
'toggle-lg': '2rem'
}
}
}
}
Add a hidden input field and update its value when the toggle changes:
<input type="hidden" name="dark-mode" value="false" id="toggle-value" />
<!-- In your JS: -->
document.getElementById('toggle-value').value = isOn;
Yes! All generated classes are compatible with JIT. If you use custom colors or sizes, ensure they're defined in your tailwind.config.js file.
Store the state in localStorage and initialize from it:
// On toggle change:
localStorage.setItem('toggleState', isOn);
// On page load:
const savedState = localStorage.getItem('toggleState');
isOn = savedState === 'true';
Last reviewed for Tailwind CSS v3.3+ compatibility. Tool updated: