.

Setting up dark mode with Tailwind CSS and Alpine.js

Intro

In this post, I walk through how I setup dark mode with Tailwind CSS and Alpine.js. This writting assumes that you are familiar with Tailwind CSS and Alpine.js and that you already have them installed.

Kicking things off

Let's get things setup for alpine to handle our user action and to facilitate localStorage setting and getting.

Add x-data and x-init to your html tag.

  • In x-data create a darkMode property that is set to the value of the localStorage darkMode, if that doesn't exists set it to false, or true if you want your default to be dark mode.
  • In x-init we are going to start a watcher, so that when the darkMode property changes we perform an action. That action will be setting the user defined value in local storage.
<html
    x-data="{ darkMode: localStorage.getItem('darkMode') || 'false' }"
    x-init="$watch('darkMode', (val) => localStorage.setItem('darkMode', val))"
>

Re: Local Storage

Now, your body is going to be where you set your dark class that Tailwind CSS provides. 🔥 I always use x-cloak when using Alpine.js to change the state of something on the page, so to avoid the "blink"

<body :class="{ 'dark': darkMode === 'true' }" x-cloak>

Now for the user action -- Let's create a simple button, add a little style and attach an event listener with Alpine.js. When the user clicks we will set darkMode to the opposite of whatever it is now and then the watcher, which we initialized in x-init, will update local storage for us.

<button type="button" @click="darkMode = (darkMode === 'true' ? 'false' : 'true')" class="rounded hover:shadow p-1 border-gray-500 border bg-black text-white dark:text-black dark:bg-white">
    <span x-show="darkMode === 'true'">Dark Mode</span>
    <span x-show="darkMode === 'false'">Light Mode</span>
</button>

That's a wrap

Thanks for reading. Hope you enjoyed. If you have any questions, just hit me up on Twitter!

<!doctype html>
<html
    x-data="{ darkMode: localStorage.getItem('darkMode') || 'false' }"
    x-init="$watch('darkMode', (val) => localStorage.setItem('darkMode', val))"
>
<head>
    <!-- Tailwind style and Alpine.js scripts -->
</head>
<body :class="{ 'dark': darkMode === 'true' }" x-cloak>
    <main class="bg-gray-100 dark:bg-black transition min-h-screen">
        <button type="button" @click="darkMode = (darkMode === 'true' ? 'false' : 'true')" class="rounded hover:shadow p-1 border-gray-500 border bg-black text-white dark:text-black dark:bg-white">
                <span x-show="darkMode === 'true'">Dark Mode</span>
                <span x-show="darkMode === 'false'">Light Mode</span>
        </button>
    </main>
</body>
</html>