Dark Mode in Next.js: A Step-by-Step Guide

6 min read

Are you looking to add a cool dark mode to your Next.js project? You're in luck because I've got a step-by-step guide to do just that using next-themes! Let's dive in.

Setting Up next-themes

First, we need to install next-themes. Run npm install next-themes in your project directory. This handy package helps manage theme switching seamlessly.

Configuring next-themes

'use client';

import { ThemeProvider } from 'next-themes';
import { ReactNode } from 'react';

export function Providers({ children }: { children: ReactNode }) {
  return <ThemeProvider attribute="class">{children}</ThemeProvider>;
}

Setting Up RootLayout

import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Providers>
          <main>{children}</main>
        </Providers>
      </body>
    </html>
  );
}

suppressHydrationWarning is used in Next.js with next-themes to prevent warnings about discrepancies between server and client renders due to theme changes, ensuring smooth hydration despite theme preferences.

I am going to use TailwindCSS to style, so let's set it up!

import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {},
  },
  darkMode: "class",
};
export default config;

Create a Theme Switcher

'use client';
import { useTheme } from 'next-themes';
import React, { useEffect, useState } from 'react';

const ThemeToggleButton = () => {
  const { theme, setTheme } = useTheme();
  const [mounted, setIsMounted] = useState(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  if (!mounted) return null;

  return (
    <button 
      aria-label="Theme Switcher" 
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
        Toogle Theme{' '}
    </button>
  );
};

export default ThemeToggleButton;

We need the mounted state to make sure that component did mount on a client side and we can use hooks

Styling for Dark and Light Mode

export default function Home() {
  return (
    <section className="mb-20 h-screen">
      <ThemeSwitcher />
      <article className="bg-white dark:bg-gray-900 rounded-md">
        <h2 className="text-gray-900 dark:text-white">Easy Dark theme</h2>
        <p className="text-gray-500 dark:text-slate-300">Next.js + next-themes</p>
      </article>
    </section>
  );
}

And there you have it! A simple yet effective way to add dark mode to your Next.js app with next-themes. Happy coding! 🌒🌓🌔