Dark mode in Next-js-13 App using Tailwind CSS: Ultimate Guide. - Nextjs Dev (2024)

Table of Contents

Hello everyone, I hope you are good and doing well. Today, we are going to discuss how we can add Dark mode in Next-js-13 App using Tailwind CSS-Beginner’s Guide. So, Let’s begin.

Having a bright screen at night is painful for our eyes. That’s why the dark mode feature is necessary if we want to take care of our user’s eyes.

In this lesson, we’ll learn how to enable Dark mode in Next-js-13 App using Tailwind CSS to keep our users engaged with our app all night long.

We will see how we can easily implement the dark mode feature by using and combining next-themes and Tailwind CSS.

And we’ll add the ability for our users to toggle between light and dark modes from the user interface.

Tech Stack used:

  1. Next.js 13 App directory
  2. Tailwind CSS
  3. React.js

Npm Packages used:

  1. next-themes
  2. @heroicons/react

Here is a little demo of the project, that we are going to build and the GitHub link to the project.

Demo Link of the Project : Dark mode in Next-js-13 App using Tailwind CSS

Github Link of the Project

Step-1: Setup a New Next.Js-13 Project

First of all, create a Next.js-13 project and install Tailwind CSS to it. Run the below command to create a new Next.js-13 app.

npx create-next-app@latest nextjs-project

Bash

After executing the above command, please select the choices according to the below-given instructions.

 Would you like to use TypeScript with this project? ... No / Yes Would you like to use ESLint with this project? ... No / Yes Would you like to use Tailwind CSS with this project? ... No / Yes Would you like to use `src/` directory with this project? ... No / Yes Would you like to use the experimental `app/` directory with this project? ... No / Yes What import alias would you like configured? ... @/*

Bash

I have chosen yes for all of them, as I will be using Typescript and Tailwind CSS with Nextjs in this project.

After that, you need to install two packagesnext-themesand@heroicons/reactfrom npm so that we can add the Dark Mode in Nextjs 13 using Tailwind CSS.

npm install next-themes @heroicons/react

Bash

Step 2: Creating Components

First of all, visit thepage.tsxfile inside the app directory delete everything inside it and paste the following code:

Insidepage.tsx(app folder):

export default function Home() { return ( <div className="flex flex-col items-center justify-center space-y-10 mt-28"> <div className="flex flex-col items-center space-y-6"> <h1 className=" max-w-3xl text-center font-bold text-gray-900 dark:text-  white text-5xl leading-tight"> Welcome to Next.js Dev,Blogging Platform for Devs. </h1> <p className="text-lg font-medium text-gray-900 dark:text-white"> Add Dark mode in the Next-js-13 App using Tailwind CSS </p> </div> <button className=" text-lg w-[180px] bg-gradient-to-r from-[#ff874f] to-  [#ec5e95] rounded-lg text-gray-50 font-semibold py-[10px] px-4"> Get Started </button> </div> );}

JavaScript

Also, change thelayout.tsxfile as well.

Inside layout.tsx file:

import "./globals.css";import Navbar from "@/components/Navbar";import Footer from "@/components/Footer";export const metadata = { title: "Next.js 13 Dark Mode with Tailwind CSS", description: "Adding Dark mode in Next-js-13 App using Tailwind CSS.",};export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body className="min-h-screen mx-auto max-w-6xl flex flex-col bg-white  dark:bg-gray-900"> <Navbar /> <main className="flex flex-col flex-1 max-w-6xl w-full "> {children} </main> <Footer /> </body> </html> );};

JavaScript

You might be getting errors about the Navbar and Footer components because we have created them yet.

So let’s create Navbar and Footer components and import them inside thelayout.tsxfile so that we can test the dark mode and light mode theme functionality in our app.

So, first of all, create acomponentsfolder in the root of the directory.

Inside thecomponents, create two files:

  1. Navbar.tsx
  2. Footer.tsx

InsideNavbar.tsx, please add the below code:/c

import Link from 'next/link'import React from 'react'const Navbar = () => { return ( <header className="h-15 w-full shadow-sm dark:border-gray-700"> <div className="container px-4 sm:px-6 py-4 flex justify-between items-center"> {/* Logo */} <h2 className='font-bold text-3xl text-gray-900 dark:text-white'> <Link href="https://nextjsdev.com" > Next.js Dev </Link> </h2> {/* Theme Switcher */} </div> </header> )}export default Navbar

JavaScript

Inside the Footer.tsx file:

import React from "react";const Footer = () => { return ( <footer className="px-4 sm:px-6 py-6 mt-10"> <div className="text-center text-sm text-gray-500"> <span className="dark:text-gray-100 text-gray-900 font-bold text-lg mr-2"> {" "} Copyright Next.js Dev - </span>{" "} © {new Date().getFullYear()} All Rights Reserved </div> </footer> );};export default Footer;

JavaScript

So in the Navbar.tsx, you can see that we have simply added a nav container and added a logo inside it. we have left some space for the ThemeSwitcher component that we will create later.

Similarly, we have created a simple Footer component as well, which contains a simple footer container with some text in it.

Next-Auth Authentication in Next.js 13 App Directory: Beginner’s Tutorial

Step-3 Creating the ThemeProvider and ThemeSwitcher

After, creating, now let’s come to the important part. If you are not aware in Next.js-13, all components that we create the files likeNavbar.tsxorFooter.tsxorpage.tsx, all of them are Server Components by default.

So, if you try to import the{ThemeProvider}form next-themes and use it inside the layout.tsx, you will get an error, because {ThemeProvider} is a ContextProvider and it will only work inside a Client Component.

This is the main thing to note, that’s why to solve this problem, we need to create two more components inside thecomponentsfolder.

  1. Provider.tsx (It will be a client component that will help to provide access to the ThemeProvider to our whole application)
  2. ThemeSwitcher (It is also a client component and will help to manually change the theme of the app)

Now let’s create theProvider.tsxandThemeSwitcher.tsxinside thecomponentsfolder

Inside Provider.tsx file:

"use client"import {ThemeProvider} from 'next-themes';import { useState, useEffect } from 'react'type Props = { children: string | React.JSX.Element | React.JSX.Element[]; }const Provider = ({children} : Props) => {const [mounted,setMounted] = useState<boolean>(false);useEffect (() => { setMounted(true);},[]);if(!mounted){ return <>{children}</>;} return ( <ThemeProvider enableSystem={true} attribute='class'> {children} </ThemeProvider> )}export default Provider;

JavaScript

Inside ThemeSwitcher.tsx file:

"use client";import { useTheme } from "next-themes";import { SunIcon } from '@heroicons/react/24/outline';import { MoonIcon } from '@heroicons/react/24/solid';const ThemeSwitcher = () => {  const {systemTheme, theme, setTheme } = useTheme(); const renderThemeChanger= () => {  const currentTheme = theme === "system" ? systemTheme : theme ; if(currentTheme ==="dark"){ return ( <SunIcon className="w-6 h-6 text-yellow-500 " role="button" onClick={() =>  setTheme('light')} /> ) } else { return ( <MoonIcon className="w-6 h-6 text-gray-900 " role="button" onClick={() =>  setTheme('dark')} /> ) } }; return ( <> {renderThemeChanger()} </> );};export default ThemeSwitcher;

JavaScript

So what’s happening here is that we used the ‘useTheme` hook from `next-themes`, along with the `MoonIcon` and the `SunIcon` components from heroicons.

Then, we retrieve the `systemTheme`, the `theme`, and the `setTheme` properties by calling `useTheme` at the top of your component.

From there, create a new method named `renderThemeChanger` and get the current theme from the system or the `theme` variable.

Now, if the current theme is dark, we return the `SunIcon` component and implement the `onClick` event by using the `setTheme` method from `next-themes` to toggle the theme back to light on click to this icon.

Otherwise, we return the `MoonIcon` component and set the theme to dark on click.

Finally, import the Provider component inside thelayout.tsxcomponent to wrap the web app to provide theThemeProvider.

Inside the layout.tsx file:

import Navbar from "@/components/Navbar";import "./globals.css";import Footer from "@/components/Footer";import Provider from "@/components/Provider";export const metadata = { title: "Next.js 13 Dark Mode with Tailwind CSS", description: "Adding Dark mode in Next-js-13 App using Tailwind CSS.",};export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body className="min-h-screen mx-auto max-w-6xl flex flex-col bg-white  dark:bg-gray-900"> <Provider> <Navbar /> <main className="flex flex-col flex-1 max-w-6xl w-full "> {children} </main> <Footer /> </Provider> </body> </html> );}

JavaScript

Ans also import the ThemeSwitcher component inside theNavbar.tsxfile, where we left the space for the the ThemeSwitcher component.

Inside the Navbar.tsx file:

After all that open thetailwind.config.jsfile and then add a property darkMode in it and give a value “class” to it like this.

Inside tailwind.config.ts file:

/** @type {import('tailwindcss').Config} */module.exports = { darkMode:"class", content: [ './pages/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}', './app/**/*.{js,ts,jsx,tsx,mdx}', ], theme: {}, plugins: [],}

JavaScript

Now, whenever, the `dark` class is present earlier in the HTML tree, tailwind CSS will apply the dark styles, otherwise, it applies the light theme by default.

After that, open the terminal and start the server, the app will be running on localhost:3000, and you might encounter an error, which will be a Hydration Error.

Step-4 Fixing Hydration Mismatch Problem

You might be wondering why we are getting a hydration mismatch error.

So to summarize in short, we cannot know the theme on the server, the values returned from `useTheme` will be `undefined` until mounted on the client.

In other words, our theme icon will not match the actual current theme. And that’s pretty bad for user experience.

So to fix this, we need to make sure we only render our icon when the page is mounted on the client.

So, import the `useState` and `useEffect` hooks from `react`. And create a new state variable to track if the component has been mounted or not on the client side.

Set the initial value to false, and then set its value to true inside a `useEffect` hook.

Finally, inside the `renderThemeChanger`, check if the component is mounted before rendering the UI for the theme changer.

Inside ThemeSwitcher.tsx file:

"use client";import { useState, useEffect } from "react";import { useTheme } from "next-themes";import { SunIcon } from '@heroicons/react/24/outline';import { MoonIcon } from '@heroicons/react/24/solid';const ThemeSwitcher = () => { const [mounted, setMounted] = useState(false); const {systemTheme, theme, setTheme } = useTheme(); // useEffect only runs on the client, so now we can safely show the UI useEffect(() => { setMounted(true); }, []); if (!mounted) { return null; } const renderThemeChanger= () => { if(!mounted) return null; const currentTheme = theme === "system" ? systemTheme : theme ; if(currentTheme ==="dark"){ return ( <SunIcon className="w-6 h-6 text-yellow-500 " role="button" onClick={() =>  setTheme('light')} /> ) } else { return ( <MoonIcon className="w-6 h-6 text-gray-900 " role="button" onClick={() =>  setTheme('dark')} /> ) } }; return ( <> {renderThemeChanger()} </> );};export default ThemeSwitcher;

JavaScript

Step-5 Checking the Dark Mode Functionality

Now that everything is all set, try to refresh the browser or restart the server.

You can now change the theme of your application manually from the UI which is what we wanted.

You can easily change those dark variants by just adding classes like this:

<h1 className="dark:bg-gray-900 dark:text-gray-100 " >This is H1 heading</h1>

HTML

Conclusion: Dark mode in Next-js-13 App using Tailwind CSS

So that was all about adding Dark mode in Next-js-13 App using Tailwind CSS.

I hope you like this and enjoyed building this project.

If you think that this was helpful then please do consider visiting my original blog link, follow me onTwitter, and connect with me onLinkedIn.

If you were stuck somewhere and not able to find the solution you can check out my completed GitHub repository here.

Thanks for the time to read this project, if you like this please share it on Twitter and Facebook or any other social media and tag me there.

Some Useful Link:

  1. Next.js and Tailwind Installation Docs
  2. Github link for the project
Dark mode in Next-js-13 App using Tailwind CSS: Ultimate Guide. - Nextjs Dev (2024)
Top Articles
Latest Posts
Article information

Author: The Hon. Margery Christiansen

Last Updated:

Views: 5754

Rating: 5 / 5 (70 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: The Hon. Margery Christiansen

Birthday: 2000-07-07

Address: 5050 Breitenberg Knoll, New Robert, MI 45409

Phone: +2556892639372

Job: Investor Mining Engineer

Hobby: Sketching, Cosplaying, Glassblowing, Genealogy, Crocheting, Archery, Skateboarding

Introduction: My name is The Hon. Margery Christiansen, I am a bright, adorable, precious, inexpensive, gorgeous, comfortable, happy person who loves writing and wants to share my knowledge and understanding with you.