Skip to main content

Command Palette

Search for a command to run...

Light and Dark Theme Using next-themes in Next.js

Updated
3 min read

Hello. hope you are doing good!

Follow this simple steps to set up theming in your application.

  1. Initialize a Next.js project.

  2. Configure all the default settings with Tailwind CSS.

npx create-next-app@latest

Setting Theme Using next-themes: System, Dark, Light

Quick Walkthrough:

  1. Install next-themes.

  2. Create a provider.

  3. Wrap the children in this provider.

  4. Update the global CSS.

  5. Create a test component and test it.

STEP 1: Install next-themes

npm install next-themes

STEP 2: Create a Client Component Provider

Create a client component named NextThemeProvider.tsx in the folder /providers.

//file-path : providers/NextThemeProvider.tsx

"use client";
import { ThemeProvider, ThemeProviderProps } from "next-themes";

export const NextThemeProvider = ({children,...props}:ThemeProviderProps)=>{
    return(
        <ThemeProvider {...props}>
            {children}
        </ThemeProvider>
    )
}

STEP 3: Wrap the Children in Layout with the Provider

Import the NextThemeProvider in your app/_layout.tsx file and wrap all the children.

app/_layout.tsx

Update the props for the NextThemeProvider.

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${interFonts.variable} antialiased suppressHydrationWarning`}
      >
        <NextThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          <main className="bg-background text-forgeground">
          {children}
          </main>
        </NextThemeProvider>
      </body>
    </html>
  );
}
  - attribute = "class" → Put class="dark" on html tag (Tailwind needs this)
  - defaultTheme = "system" → Start with users OS theme (light/dark)
  - enableSystem = → Let users pick "follow my OS theme" option

Also, you need to configure the global.css in your root folder.

STEP 4: Import in Global CSS

@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *)); 
//Add this line so it correclty configure tailwind classes

STEP 5: Create a Test Component

Create a component called ThemeChanger.tsx.

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

export  const ThemeChanger = () => {
  const { theme, setTheme } = useTheme();

  return (
    <div>
      The current theme is: {theme}
      <button onClick={() => setTheme('light')} className='text-md bg-[#97b1ab] p-1 rounded-xl'>Light Mode</button>
      <button onClick={() => setTheme('dark')} className='text-md bg-[#97b1ab] p-1 rounded-xl'>Dark Mode</button>
    </div>
  )
}

Now import this in your app/page.tsx.

import {ThemeChanger} from "@/components/test-theme";

export default function Home() {
  return (
    <div className="flex">
      <p>Hello. Started with my mini portfolio.</p>
      <ThemeChanger/>
    </div>
  );
}

Quick Notes

  • Once the user toggles the button, the local storage stores the user preference, and it won’t default to the system theme.

  • If you want to check whether the default system theme is working or not, clear the local storage and set your browser appearance to auto/system in Chrome, and the changes will reflect.

  • There might be issues with the Brave browser where the system default theme is not visible, only the light and dark themes.

Adding Fonts to the Application

If you've ever wondered what the variables and subsets do in the fonts of the Next.js layout file:

  • Variables: These are CSS variables that Next.js loads, which can be used in Tailwind classes.

  • Subsets: These are groups of characters in a specific font.

//In app/layout.tsx
//import the font you want to use 
import { Inter } from "next/font/google";

const interFonts = Inter({
  variable:"--font-inter",
  subsets:["latin"],
});

//Pass the font to rootLayout
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${interFonts.variable} antialiased suppressHydrationWarning`}
      > 
          {children}
      </body>
    </html>
  );
}
Examples:

latin → English letters
latin-ext → accented European chars
devanagari → Hindi
cyrillic → Russian
arabic → Arabic

hope this helpful :) do subscribe for more blogs have a great time building your project!