Add dark mode to your Nuxt 3 app in 15 mins
I'll show you how to add dark mode to your Nuxt app quickly with VueUse and TailwindCSS.
Introduction
👋 Hi all, we will be extending our blog to add dark mode to it but this will apply to any Nuxt 3 app easily as well.
If you are following us from our creating a blog articles, you should already have Tailwind and VueUse installed and you can skip to Setting up Tailwind for dark mode.
Styling with Tailwind CSS
We will be using Tailwind CSS to style our blog including dark mode. Installation is made easy with Nuxt Tailwind by running this command in your terminal.
pnpm i -D @nuxtjs/tailwindcss
When installation is completed, load the package in the nuxt.config.ts file
// nuxt.config.tsexport default defineNuxtConfig({ modules: ["@nuxtjs/tailwindcss"],});
✨ That's it! We now have the power to style our blog including dark mode and all we need is to implement the logic for auto and manual selection of the mode.
Using VueUse
We will be using the VueUse pacakge that has a collection of composition utilities with one that will help us to implement the dark mode logic. To install the VueUse package, run the following command in a terminal inside your project folder.
pnpm i -D @vueuse/nuxt @vueuse/core
Once completed, make sure to add the package inside your nuxt.config.ts
file.
//nuxt.config.tsexport default defineNuxtConfig({ modules: ["@nuxtjs/tailwindcss", "@vueuse/nuxt"],});
Setting up Tailwind for dark mode
Let's setup Tailwind CSS to be ready for dark mode! Head over to tailwind.config.js
file and input the following:
//tailwind.config.js/** @type {import('tailwindcss').Config} */export default { darkMode: "class", // Add this line for dark mode //...rest of the code};
Update your layout for dark mode
We can now use Tailwind CSS for dark mode and I will be applying it in our layouts/Default.vue
file for a dark background.
//layouts/Default.vue<template> <div class="min-h-screen dark:bg-gray-900"> <!-- Added dark:bg-gray-900 for dark mode --> <!-- ...rest of the code --> </div></template>
Toggling color mode
I will be using the Heroicons by Tailwind as the button to toggle between dark and light mode. You can install it with the command below in a terminal in your Nuxt project.
pnpm install @heroicons/vue
We can now use the icons and I will be adding it inside components/SiteHeader.vue
of our blog app, but you can do so at any vue file.
//components/SiteHeader.vue<script lang="ts" setup>import { SunIcon, MoonIcon } from "@heroicons/vue/24/solid"; // Import our heroicons for useconst isDark = useDark(); // VueUse function to initialize and check if its dark modeconst toggleDark = useToggle(isDark); // VueUse function to toggle between the color mode</script><template> <header> <!-- ...rest of the code --> <div class="max-w-lg mx-auto flex justify-center my-3"> <button class="rounded-md p-1.5 transition-colors hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800" aria-label="Change color mode" @click="toggleDark()" > <client-only> <!-- This is to make sure the right icon is render only in client-side --> <MoonIcon class="h-5 w-5" v-if="isDark" /> <SunIcon class="h-5 w-5" v-else/> </client-only> </button> </div> </header></template>
✨ We have now succesfully added dark mode to our app and you should see the background turn dark! Reload the page and notice that the dark mode stays even after reloading. That's because VueUse useDark function persist the data using localStorage.
However, you will also notice that the rest of the content are not yet styled for the dark mode. You can use the useDark
function and Tailwind CSS dark:
syntax to style them like what we did for the background.
Color mode bug on reload
If you reload the page in dark mode, you will notice that the light mode flashes for a second before the page turn dark. That's because our useDark
initialization is called after the page finish loading. Hence we will need to find a way to initialize it before the page load.
To do so, we will add javascript to our Nuxt app in the <head>
tag ensuring the color mode is set correctly before the page finish loading. You can check out this article here on ways to do so. I will be using the useHead
method in our app.vue
file.
//app.vue<script setup lang="ts">useHead({ script: [ { children: `localStorage.getItem("vueuse-color-scheme") == 'dark' ? document.documentElement.classList.add("dark") : document.documentElement.classList.remove("dark");`, }, ], });</script><template> <NuxtLayout> <NuxtPage /> </NuxtLayout></template>
In our code, we retrieve the value of vueuse-color-scheme
from the localStorage and add the dark
class to our html
tag. This is actually what useDark
does under the hood where it save the dark mode value under vueuse-color-scheme
.
✨ Reload the page now and you can see that the white flash is gone! We have now successfully added dark mode to our app!
What's next?
Download the complete code here at Github.
Check out more related articles below!
Create a Nuxt 3 Content blog with Tailwind CSS in one hour.
3 ways to add javascript in the head tag of your Nuxt 3 app.
Add table of contents to your Nuxt 3 blog in 10 mins.
Deploy your Nuxt 3 app with Vercel for free in 5 mins