Easy Dark Mode Toggler

If you're also a fan of both the Laravel TALL stack and Dark Mode, then this one is for you. In just three simple steps, we will add an elegant way of adding support for Dark Mode into our Laravel application. Whether Taylor likes it or not ;-)

Laravel1 / 3Level:

Let's face it: Dark Mode is everywhere. And for good reason, especially when coding after dawn. However, if you've ever installed Laravel Jetstream, or heard Taylor Otwell's opinion on dark mode, then you'll probably know it's not available by default (or at least no button for toggling).

Step 1

Create a file called Theme.js inside of /resources/js with the following content:

export default new class Theme {
    set(theme) {
        theme = theme || this.get();
        localStorage.theme = theme;
        theme === 'light'
            ? document.documentElement.classList.remove('dark')
            : document.documentElement.classList.add('dark');
    get() {
        return localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
            ? 'dark'
            : 'light';

Step 2

Now inside of ./bootstrap.js (or ./app.js), we will add the following:

import Theme from './Theme.js';
window.Theme = Theme;

Step 2½

This doesn't really count as a step, but don't forget to update your tailwind.config.js file to set the darkMode property to class:

export default {
    darkMode: 'class',
    // other config...

Step 3

Assuming you've got the latest version of Laravel Livewire installed (or Alpine), we will add the following in our Blade components:

<button type="button" x-data="{ theme: Theme.get() }" @click="theme = theme === 'light' ? 'dark' : 'light'; Theme.set(theme);">
    <x-heroicon-o-moon class="w-5 h-5" x-show="theme == 'light'" />
    <x-heroicon-o-sun class="w-5 h-5" x-show="theme == 'dark'" />
By the way, I'm using Heroicons for those who are curious.

That's pretty much it. We've made the Theme JavaScript function available throughout our application and then use Alpine to retrieve it. When a user clicks on the button, we update the state of the theme.

I've found this to be a simple way to benefit from both custom JavaScript and Livewire/Alpine's capabilities to retrieve it.

Hope you enjoyed this tip and I see you around! ✌🏻