Enable Dark Mode in Tailwind + Laravel and Vue - 2 WAYS

Video thumbnail

I am going to show you how you can enable dark mode in Tailwind, regardless of whether you are using Laravel, Vue, or both. In my case, I use a Laravel project with a Vue section and, of course, I take advantage of Tailwind classes.

The first thing you should keep in mind is that Tailwind allows you to manage dark mode very easily through its configuration file.

1. Initial Configuration, darkMode

To begin, we must modify the tailwind.config.js file. By default, Tailwind detects dark mode according to the operating system settings, but if we want the user to choose it manually, we must configure it by class:

// tailwind.config.js
module.exports = {
 darkMode: 'class', // Enables manual switching via a CSS class
 // ...
}

2. Activation via JavaScript (Toggle)

The logic is very simple: Tailwind will activate dark styles whenever the root <html> tag has the .dark class.

If you use Vue, you can trigger a function via a click event to modify the DOM directly. Here is how to do the toggle:

// In your Vue component
methods: {
 darkModeToggle() {
   // Adds or removes the "dark" class from the HTML element
   document.querySelector("html").classList.toggle("dark");
   
   // We change the reactive state to update icons or labels
   this.isDarkMode = !this.isDarkMode;
 }
}

In the template, the button would look like this:

<button class="translate-y-1" @click="darkModeToggle">
 </button>

3. Applying Styles in HTML and CSS

Once the .dark class is active on the <html> tag, you can define specific colors using the dark: prefix.

In HTML components: If you have a link that is purple in light mode, but you want it to be white in dark mode, you do it like this: class="text-purple-700 dark:text-white"

In stylesheets (CSS): If you prefer to use an external stylesheet, it is also very simple:

.my-card {
 @apply bg-white dark:bg-gray-800 text-black dark:text-gray-100;
}

4. Persisting the Choice

Since we are in an SPA application with Vue, the change works correctly while you navigate. However, if you reload the page, the user's choice will be lost. To make this persistent, you have several paths that depend on your technology and not on Tailwind:

  • LocalStorage or Cookies: Store the preference directly in the browser.
  • Database: If the user is authenticated (as in Laravel), you can save their preference in the database so that their session always starts with the chosen mode.

How to Create a Dark Mode Toggle with Tailwind 4 (Laravel Livewire)

How to Create a Dark Mode Toggle with Tailwind 4 (Laravel Livewire)
Video thumbnail

Gothic mode... sorry, dark mode in Tailwind 4. How do we implement it? We're going to save the configuration directly to the session, i.e., the mode. For this, we'll use Laravel Livewire, but first, let's see what we need to do for Tailwind 4.

Toggle Dark/Light Mode in Tailwind 4

It works similarly to how we did with Tailwind 3, at least as far as CSS classes are concerned. However, there's a new consideration in Tailwind 4, which I'll explain below.

If you select any rule that uses the dark: prefix from the browser, you'll see something like this:

dark\:bg-gray-800 {
   @media (prefers-color-scheme: dark) {
       background-color: var(--color-gray-800);
   }
}

In Tailwind 4, the default system uses @media (prefers-color-scheme), which detects the operating system or browser mode. This can't be controlled from JavaScript, so a toggle like ours wouldn't have any effect if we left the default settings.

We must override it with the following rule in our CSS where we load Tailwind 4:

resources\css\YOURCSS.css

@import 'tailwindcss';
+ @custom-variant dark (&:where(.dark, .dark *));

With this, we can easily switch between modes by changing the class of the HTML tag from the browser:

// document.documentElement.className = params[0].theme;
document.documentElement.classList.toggle('dark');

Create the Theme Toggle Component in Laravel Livewire

Let's create a component that allows us to toggle between light mode and dark mode. It's also important to note that Flux handles its own logic for the dark theme.

$  php artisan make:livewire ThemeToggle

app\Livewire\ThemeToggle.php

<?php

namespace App\Livewire;

use Livewire\Component;

class ThemeToggle extends Component
{
    public $theme;

    public function mount()
    {
        $this->theme = session('theme', 'light');
    }

    public function toggleTheme()
    {
        $this->theme = $this->theme === 'light' ? 'dark' : 'light';
        session(['theme' => $this->theme]);
        $this->dispatch('theme-changed', ['theme' => $this->theme]);
    }

    public function render()
    {
        return view('livewire.theme-toggle');
    }
}

If you search for "Flux dark mode," for example, you'll see that it has its own switcher (Dark/System/Light), but that's not what we're going to use here. I want to use a custom implementation, as I prefer to keep this website as lightweight as possible and without too many dependencies. I don't want to add unnecessary additional JavaScript for the end user.

I prefer something more controlled. Tailwind is already more than enough, and perhaps a few additional scripts or CSS, like Flux in this case for certain styles. But I don't want this course to be so dependent on external technologies that are constantly changing, as is the case with Laravel.

If no value is defined, we set a default value (in this case, light, although you can set dark if you prefer):

$this->theme = session('theme', 'light');

If the current mode is light, change to dark, and vice versa:

$this->theme = $this->theme === 'light' ? 'dark' : 'light';

Set the new value in the session and dispatch an event to the client to apply the changes.
We could also reload the page, although there are many ways to do this:

$this->dispatch('theme-changed', ['theme' => $this->theme]);
***
Livewire.on('theme-changed', (params) => {
    // document.documentElement.className = params[0].theme;
    document.documentElement.classList.toggle('dark');
})

The button's view is simple. We'll place a button "Change Mode":

<div>
    <flux:button wire:click="toggleTheme">
        {{ __('Change mode') }} {{ $theme === 'light' ? __('Dark'): __('Light') }}
    </flux:button>
</div>

The button displays "Dark" or "Light" depending on the active mode, but remember that it must be the option you're switching to, not the current one. That is, if the current mode is light, the button should say Dark.

I agree to receive announcements of interest about this Blog.

We will see the two ways to enable dark mode, through the tailwind.config file and by selection using the dark class and I'll show you a few simple steps to use dark mode in Tailwind 4 and also in Laravel Livewire.

| 👤 Andrés Cruz

🇪🇸 En español