alpine-js
Using Alpine and Tailwind for Easy Dark Mode Toggle
Creating a dark mode toggle has never been easier thanks to Alpine.js and Tailwind CSS. This guide walks you through building one from scratch.
#Prerequisites
Before diving in, ensure you have Alpine.js set up in your project.
👉 Alpine.js Installation Guide
Refer to their documentation for a fast and easy installation.
#How It Works
We’re going to:
- Check if the user has a saved dark mode preference in
localStorage
- Fall back to the browser's default color scheme if no preference is set
- Use Alpine.js to toggle dark mode and persist the choice
- Style everything with Tailwind CSS
#Wiring Up Alpine.js
Once Alpine is ready, wire up the logic directly on the <body>
tag:
<body x-data="{ darkMode: localStorage.theme === 'dark' || (!localStorage.theme && window.matchMedia('(prefers-color-scheme: dark)').matches) }" x-init="$watch('darkMode', val => localStorage.theme = val ? 'dark' : 'light')" :class="{ 'dark': darkMode }" class="font-sans antialiased bg-white dark:bg-black" >
This setup ensures your site respects user preferences and remembers them between visits.
#Configuring Tailwind for Dark Mode
#Tailwind CSS v3
Add this to your tailwind.config.js
file:
darkMode: 'class'
#Tailwind CSS v4
With v4, dark mode is handled in your CSS instead:
@custom-variant dark (&:is(.dark *));
This enables dark styles when .dark
is present anywhere in the DOM tree.
#Creating the Toggle Button
Let’s build a reusable button that switches modes with a click:
<button title="Toggle dark mode" @click="darkMode = !darkMode" class="p-2 cursor-pointer text-neutral-600 hover:text-black dark:text-neutral-300 dark:hover:text-white" > <svg x-show="darkMode" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" /> </svg> <svg x-show="!darkMode" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" /> </svg> </button>
These SVG icons come from Heroicons, providing a sun and moon icon for light and dark modes.
#Bonus Tips
- Extract the toggle into its own component if you're using a component-based framework.
- Place the button in your navbar for easy access.
- Animate the icon change for a smoother UX.
#Final Thoughts
That’s it! With just a bit of Alpine.js and Tailwind, you’ve built a fully functional, persistent dark mode toggle.
Happy coding!!