Light and Dark Theme Using next-themes in Next.js
Hello. hope you are doing good!
Follow this simple steps to set up theming in your application.
Initialize a Next.js project.
Configure all the default settings with Tailwind CSS.
npx create-next-app@latest
Setting Theme Using next-themes: System, Dark, Light
Quick Walkthrough:
Install next-themes.
Create a provider.
Wrap the children in this provider.
Update the global CSS.
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!