TailwindCSS 4 out the box supports prefers-color-scheme
CSS media feature, I want class based dark mode support. To enable this add the following to your resources/css/app.css
file
@custom-variant dark (&:where(.dark, .dark *));
This allows dark mode when the HTML tag has a class of dark.
Next create a toggle button. These has 2 icons for light mode and dark mode. Light is hidden by default. By adding a hidden class.
I’m using Heroicons that can be installed via blade-ui-kit/blade-heroicons
<button id="theme-toggle" class="p-2">
<x-heroicon-o-sun id="theme-toggle-light" class="hidden size-5 text-yellow-500" />
<x-heroicon-o-moon id="theme-toggle-dark" class="size-5 text-gray-900 dark:text-white" />
</button>
Next we need Javascript to handle click events when either icon is pressed.
Create a new file resources/js/dark.js
reference it inside the resources/js/app.js
file
import './dark';
Inside dark.js
add:
document.addEventListener("DOMContentLoaded", applyTheme); // Fires on page load
document.addEventListener("livewire:navigated", applyTheme); // Fires for Livewire navigation
window.addEventListener("popstate", applyTheme); // Detects manual URL changes
function applyTheme() {
const themeToggle = document.getElementById("theme-toggle");
const themeToggleLight = document.getElementById("theme-toggle-light");
const themeToggleDark = document.getElementById("theme-toggle-dark");
function setTheme(mode) {
if (mode === "dark") {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
if (themeToggleLight && themeToggleDark) {
themeToggleLight.classList.remove("hidden");
themeToggleDark.classList.add("hidden");
}
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
if (themeToggleLight && themeToggleDark) {
themeToggleDark.classList.remove("hidden");
themeToggleLight.classList.add("hidden");
}
}
}
// Check saved theme or use system preference if no saved theme
const savedTheme = localStorage.getItem("theme");
if (savedTheme) {
setTheme(savedTheme); // Apply the saved theme
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
setTheme("dark"); // Apply dark mode based on system preference
} else {
setTheme("light");
}
// Add event listener for the theme toggle button
if (themeToggle && !themeToggle.dataset.listenerAdded) {
themeToggle.addEventListener("click", () => {
const isDark = document.documentElement.classList.contains("dark");
setTheme(isDark ? "light" : "dark");
});
themeToggle.dataset.listenerAdded = true; // Prevent duplicate event listeners
}
}
Now rebuild your assets npm run build
Now clicking on either icon should toggle the dark / light mode. Also the site will honor the visitors system preferences by default so if they are using dark mode, dark mode will load by default.