Toggles
Ready to use Tailwind CSS toggle components with production-ready, copy-paste HTML code. Use them as they are, or as a starting point to build beautiful websites.
Toggles are basically fancy on/off switches. They're better than a checkbox when you want the action to feel immediate, like flipping a setting, enabling a feature, or switching between two states. We have a standard toggle, a thinner/more compact version, toggles with a label on the left or right, and one with both a label and a description underneath. They all include the vanilla JavaScript to handle the click and aria-checked state, so they're accessible and work out of the box.
<button id="toggle" class="group inline-flex h-6 w-11 rounded-full border-2 border-gray-200 bg-gray-200 transition-colors duration-200 ease-in-out focus:ring-2 focus:ring-pink-500 focus:ring-offset-2 focus-visible:outline-none data-[checked]:border-pink-500 data-[checked]:bg-pink-500 sm:data-[checked]:hover:border-pink-600 sm:data-[checked]:hover:bg-pink-600" role="switch" type="button" aria-checked="false">
<span class="sr-only">Remember me</span>
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transition-all duration-200 ease-in-out group-data-[checked]:translate-x-5"></span>
</button>
const toggleButton = document.querySelector("#toggle");
const toggleHandler = (event) => {
const button = event.target;
const isChecked = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", !isChecked);
if (!isChecked) {
button.setAttribute("data-checked", "");
} else {
button.removeAttribute("data-checked");
}
};
toggleButton.addEventListener("click", toggleHandler);
<button id="toggle" class="group relative isolate inline-flex h-6 w-11 rounded-full border-2 border-white bg-white focus:ring-2 focus:ring-pink-500 focus:ring-offset-2 focus-visible:outline-none" role="switch" type="button" aria-checked="false">
<span class="sr-only">Remember me</span>
<span aria-hidden="true" class="pointer-events-none absolute left-1/2 top-1/2 -z-10 h-2.5 w-9 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gray-200 transition-colors duration-200 ease-in-out data-[checked]:border-pink-500 group-data-[checked]:bg-pink-500 sm:group-data-[checked]:group-hover:bg-pink-600"></span>
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-all duration-200 ease-in-out group-data-[checked]:translate-x-5"></span>
</button>
const toggleButton = document.querySelector("#toggle");
const toggleHandler = (event) => {
const button = event.target;
const isChecked = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", !isChecked);
if (!isChecked) {
button.setAttribute("data-checked", "");
} else {
button.removeAttribute("data-checked");
}
};
toggleButton.addEventListener("click", toggleHandler);
<div class="flex w-full max-w-xs items-center justify-between gap-x-3">
<span class="text-base font-medium text-gray-900" id="toggle-label">Notifications</span>
<button id="toggle" class="group inline-flex h-6 w-11 shrink-0 rounded-full border-2 border-gray-200 bg-gray-200 transition-colors duration-200 ease-in-out focus:ring-2 focus:ring-pink-500 focus:ring-offset-2 focus-visible:outline-none data-[checked]:border-pink-500 data-[checked]:bg-pink-500 sm:data-[checked]:hover:border-pink-600 sm:data-[checked]:hover:bg-pink-600" role="switch" type="button" aria-checked="false" aria-labelledby="toggle-label">
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transition-all duration-200 ease-in-out group-data-[checked]:translate-x-5"></span>
</button>
</div>
const toggleButton = document.querySelector("#toggle");
const toggleHandler = (event) => {
const button = event.target;
const isChecked = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", !isChecked);
if (!isChecked) {
button.setAttribute("data-checked", "");
} else {
button.removeAttribute("data-checked");
}
};
toggleButton.addEventListener("click", toggleHandler);
<div class="flex items-center justify-center gap-x-3">
<button id="toggle" class="group inline-flex h-6 w-11 shrink-0 rounded-full border-2 border-gray-200 bg-gray-200 transition-colors duration-200 ease-in-out focus:ring-2 focus:ring-pink-500 focus:ring-offset-2 focus-visible:outline-none data-[checked]:border-pink-500 data-[checked]:bg-pink-500 sm:data-[checked]:hover:border-pink-600 sm:data-[checked]:hover:bg-pink-600" role="switch" type="button" aria-checked="false" aria-labelledby="toggle-label">
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transition-all duration-200 ease-in-out group-data-[checked]:translate-x-5"></span>
</button>
<span class="flex items-center gap-x-2" id="toggle-label">
<span class="text-base font-medium text-gray-900">Annual pricing</span>
<span class="rounded-md bg-gray-50 px-1.5 py-1 text-xs font-medium text-gray-700 ring-1 ring-inset ring-gray-200">Save 30%</span>
</span>
</div>
const toggleButton = document.querySelector("#toggle");
const toggleHandler = (event) => {
const button = event.target;
const isChecked = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", !isChecked);
if (!isChecked) {
button.setAttribute("data-checked", "");
} else {
button.removeAttribute("data-checked");
}
};
toggleButton.addEventListener("click", toggleHandler);
<div class="flex max-w-md items-start justify-start gap-x-3">
<button id="toggle" class="group inline-flex h-6 w-11 shrink-0 rounded-full border-2 border-gray-200 bg-gray-200 transition-colors duration-200 ease-in-out focus:ring-2 focus:ring-pink-500 focus:ring-offset-2 focus-visible:outline-none data-[checked]:border-pink-500 data-[checked]:bg-pink-500 sm:data-[checked]:hover:border-pink-600 sm:data-[checked]:hover:bg-pink-600" role="switch" type="button" aria-checked="false" aria-labelledby="toggle-label" aria-describedby="toggle-description">
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transition-all duration-200 ease-in-out group-data-[checked]:translate-x-5"></span>
</button>
<span class="flex flex-col">
<span class="text-base font-medium text-gray-900" id="toggle-label">Enable notifications</span>
<span class="mt-0.5 text-base text-gray-600" id="toggle-description">Get real-time updates about important activities.</span>
</span>
</div>
const toggleButton = document.querySelector("#toggle");
const toggleHandler = (event) => {
const button = event.target;
const isChecked = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", !isChecked);
if (!isChecked) {
button.setAttribute("data-checked", "");
} else {
button.removeAttribute("data-checked");
}
};
toggleButton.addEventListener("click", toggleHandler);
Frequently asked questions
-
A standard toggle, a thin/compact toggle, toggles with a label positioned on the left or right, and a toggle with both a label and a description for more context.
-
Yes, and it's already included. Each toggle component comes with vanilla JavaScript that handles the click, toggles the aria-checked attribute, and updates the visual state. Just copy the full snippet.
-
Toggles work best when the action feels like flipping a switch, think enabling dark mode, turning notifications on or off, or activating a feature. Checkboxes are better for selecting from a list of options.
-
Yes. They use role="switch" and aria-checked attributes. The included JavaScript keeps the aria state in sync with the visual state so screen readers announce it correctly.
-
The visual toggling works as-is. To persist the state, add your own logic inside the click handler, a fetch call, a form submission, localStorage, whatever fits your setup.
Related Tailwind CSS components
More free, copy-paste Tailwind CSS components to use in your projects.