DEV Community

Cover image for Implementing Dark Mode in Next.js with Tailwind CSS
Chinmay Mhatre
Chinmay Mhatre

Posted on • Updated on

Implementing Dark Mode in Next.js with Tailwind CSS

Dark mode has become an increasingly popular feature in web applications. With Next.js and Tailwind CSS, adding dark mode to your application is a breeze.

In this post, we'll walk through how to implement dark mode in a Next.js application using Tailwind CSS and the next-themes library.

Result

Setting up the Project

To get started, we need a Next.js application with Tailwind CSS configured. You can use the following command to create a new Next.js app with Tailwind CSS:

   npx create-next-app -e with-tailwindcss appname
Enter fullscreen mode Exit fullscreen mode

This will create a new Next.js app with Tailwind CSS configured.

Implementing Dark Mode

Next.js makes it easy to implement dark mode using the dark variant in Tailwind CSS. You can prepend dark: to properties to indicate that they are for dark mode. For example, you can use dark:bg-gray-900 to change the background color to gray-900 when the theme is set to dark.

By default, Next.js uses the system preferences to set the theme. However, we also need to toggle between light and dark modes. To do this, we can set the darkMode strategy to class in the tailwind.config.js file:

module.exports = {
  darkMode: 'class',
  // ...
}
Enter fullscreen mode Exit fullscreen mode

With this configuration, Tailwind CSS will apply the theme when the dark class is present in the HTML tree.

Using next-themes

We need to toggle between and store the current theme somehow so that when user comes back it doesn't reset to default. One way of doing this could be with local storage and doing DOM manipulation.

In this blog, we'll do something way simpler and use next-themes which handles all the toggling and storing of our preference.

To install the library, run:

npm i next-themes
Enter fullscreen mode Exit fullscreen mode

In the _app.js file, wrap your component with the ThemeProvider from next-themes. Set the attribute prop to class to allow the library to apply the theme to the HTML element.

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { ThemeProvider } from "next-themes"

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider attribute="class">
      <Component {...pageProps} />
    </ThemeProvider>
  )
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

Accessibility Considerations

It's important to ensure that your application is accessible in both light and dark mode. When choosing text and background colors, make sure that they have sufficient contrast. You can test the accessibility of your application using a tool like the Accessibility Insights browser extension.

Adding some Global Styles

We can add some global styles to global.css. Here we set the background of the body to white in light mode and dark gray in dark mode.

@layer base{
    body {
        @apply dark:bg-gray-800 bg-white
    }
}
Enter fullscreen mode Exit fullscreen mode

Adding a Toggle Button

To allow users to toggle between light and dark modes, we need to add a toggle button to our application.

We use the useTheme hook to know what the current theme is, change the current theme using the setTheme method, and the system theme.

Initially, we set the theme to the system theme.

The onclick event on the button toggles between the themes. We add some individual class using the dark: variant for the button.

"use client"
import React from 'react'
import { useTheme } from "next-themes";


const Button = () => {
    const { systemTheme, theme, setTheme } = useTheme();
    const currentTheme = theme === 'system' ? systemTheme : theme;

    return (
        <button
            onClick={() => theme == "dark"? setTheme('light'): setTheme("dark")}
            className='bg-gray-800 dark:bg-gray-50 hover:bg-gray-600 dark:hover:bg-gray-300 transition-all duration-100 text-white dark:text-gray-800 px-8 py-2 text-2xl md:text-4xl rounded-lg absolute bottom-32'>
            Toggle Mode
        </button>
    )
}

export default Button
Enter fullscreen mode Exit fullscreen mode

Adding Elements to Index.tsx

We add the toggle button to index.tsx.


      <main className="flex items-center justify-center h-screen flex-col">
        <h2 className={`${roboto.className} text-4xl sm:text-6xl md:text-9xl text-center text-gray-800`}>LIGHT MODE</h2>
        <h2 className={`${roboto.className} text-4xl sm:text-6xl md:text-9xl text-center text-white `}>DARK MODE</h2>
        <Button/>
      </main>

Enter fullscreen mode Exit fullscreen mode

Voila! Let there be light...
cat meme

Find the complete project here.

Top comments (7)

Collapse
 
aadarsh805 profile image
Aadarsh Thakur

Love the gif at the end 😸

Collapse
 
chinmaymhatre profile image
Chinmay Mhatre

Can't go wrong with a cat gif!

Collapse
 
kumosal profile image
Sami Kamal

didn't work for me.. using nextjs13 App directory

Collapse
 
chinmaymhatre profile image
Chinmay Mhatre

Thanks for bring this up. I'll update the blog soon with additional steps. For now, you could use the github readme. It has a section on setting it up with the app directory github.com/pacocoursey/next-themes

Collapse
 
kumosal profile image
Sami Kamal

I tried that but didn't work for me in a new installation.

Thread Thread
 
chinmaymhatre profile image
Chinmay Mhatre

Since the app dir is in beta. next-themes is still being worked on . There is an open issue. In case you keep facing the error. There is a support issue open. You could ask your query here. github.com/pacocoursey/next-themes... .

Collapse
 
lukahukur profile image
Luka Donadze

cool man, cool