Getting Started

$ pnpm add nextjs-themes

or

$ npm install nextjs-themes

or

$ yarn add nextjs-themes

npm bundle size Version Downloads

$ pnpm add nextjs-themes-lite

or

$ npm install nextjs-themes-lite

or

$ yarn add nextjs-themes-lite

Note: r18gs is a peer dependency

To add dark mode support, modify _app.js as follows:

import { ThemeSwitcher } from "nextjs-themes";

function MyApp({ Component, pageProps }) {
return (
<>
<ThemeSwitcher forcedTheme={Component.theme} />
<Component {...pageProps} />
</>
);
}

export default MyApp;

⚡🎉Boom! Dark mode is ready in just a couple of lines!

Update app/layout.jsx to add ThemeSwitcher from nextjs-themes:

// app/layout.jsx
import { ThemeSwitcher } from "nextjs-themes";

export default function Layout({ children }) {
return (
<html lang="en">
<head />
<body>
<ThemeSwitcher />
{children}
</body>
</html>
);
}

Woohoo! Multiple theme modes with Server Components support!

Next.js app supports dark mode, including System preference with prefers-color-scheme. The theme is synced between tabs, modifying the data-theme attribute on the html element:

:root {
--background: white;
--foreground: black;
}

[data-theme="dark"] {
--background: black;
--foreground: white;
}

Configuring nextjs-themes is super simple. You can use following props to configure the main ThemeSwitcher component.

export interface ThemeSwitcherProps {
/**
* Forced theme name for the current page
* @see [Force per page theme and color-scheme](https://github.com/react18-tools/nextjs-themes?tab=readme-ov-file#force-per-page-theme-and-color-scheme)
*/
forcedTheme?: string;
/**
* Forced color scheme for the current page
* @see [Force per page theme and color-scheme](https://github.com/react18-tools/nextjs-themes?tab=readme-ov-file#force-per-page-theme-and-color-scheme)
*/
forcedColorScheme?: ColorSchemeType;
/**
* CSS selector for the target element to apply the theme.
* Use this to specify a different target element than the default (html or documentElement).
* This is particularly useful for controlling the theme of different parts of the page independently.
*/
targetSelector?: string;
/**
* The transition property to enforce on all elements, preventing unwanted transitions during theme changes.
* @example 'background .3s'
* @defaultValue 'none'
*/
themeTransition?: string;
/**
* Provide a styles object imported from CSS/SCSS modules if you are using these modules to define theme and color-scheme classes.
* All classes applied to the target are modified using the styles object as follows:
* `if (styles) classes = classes.map(cls => styles[cls] ?? cls);`
*/
styles?: Record<string, string>;
/** The nonce value for your Content Security Policy. */
nonce?: string;
}

To augment the functionality, we also provide ForceTheme and ForceColorScheme components that effectively apply the forcedTheme and forcedColorScheme props via internal state variable. Please note that the props passed to the ThemeSwitcher has the highest priority.

Show different images based on the current theme:

import Image from "next/image";
import { useTheme } from "nextjs-themes/hooks";

function ThemedImage() {
const { resolvedTheme } = useTheme();
const src = resolvedTheme === "light" ? "/light.png" : "/dark.png";
return <Image src={src} width={400} height={400} />;
}

export default ThemedImage;

The useTheme hook provides theme information and allows changing the theme:

import { useTheme } from "nextjs-themes/hooks";

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

return (
<div>
The current theme is: {theme}
<button onClick={() => setTheme("light")}>Light Mode</button>
<button onClick={() => setTheme("dark")}>Dark Mode</button>
</div>
);
};

The useTheme hook returns the following object:

interface UseThemeYield {
theme: string;
darkTheme: string;
lightTheme: string;
colorSchemePref: ColorSchemeType;
systemColorScheme: ResolvedColorSchemeType;
resolvedColorScheme: ResolvedColorSchemeType;
resolvedTheme: string;
setTheme: (theme: string) => void;
setDarkTheme: (darkTheme: string) => void;
setLightTheme: (lightTheme: string) => void;
setThemeSet: (themeSet: { darkTheme: string; lightTheme: string }) => void;
setColorSchemePref: (colorSchemePref: ColorSchemeType) => void;
toggleColorScheme: (skipSystem?: boolean) => void;
setForcedTheme: (forcedTheme: string) => void;
setForcedColorScheme: (forcedColorScheme: ColorSchemeType) => void;
}

Force per page theme and color-scheme

import { ForceTheme } from "nextjs-themes/force-theme";

function MyPage() {
return (
<>
<ForceTheme theme="my-theme" />
...
</>
);
}

export default MyPage;

If you are using TypeScript and have not set nodeResolution to Bundler or Node16 or NodeNext, you need to import from nextjs-themes/client/force-theme

For the pages router, you have two options. The first option is the same as the app router, and the second option, which is compatible with next-themes, involves adding the theme property to your page component like this:

function MyPage() {
return <>...</>;
}

MyPage.theme = "my-theme";

export default MyPage;

Similarly, you can force a color scheme. This will apply your defaultDark or defaultLight theme, which can be configured via hooks.

Next Themes works with any library. For Styled Components, createGlobalStyle in your custom App:

// pages/_app.js
import { createGlobalStyle } from "styled-components";
import { ThemeSwitcher } from "nextjs-themes";

const GlobalStyle = createGlobalStyle`
:root {
--fg: #000;
--bg: #fff;
}

[data-theme="dark"] {
--fg: #fff;
--bg: #000;
}
`;

function MyApp({ Component, pageProps }) {
return (
<>
<GlobalStyle />
<ThemeSwitcher forcedTheme={Component.theme} />
<Component {...pageProps} />
</>
);
}

In tailwind.config.js, set the dark mode property to class:

// tailwind.config.js
module.exports = {
darkMode: "class",
};

⚡🎉Ready to use dark mode in Tailwind!

Caution: Your class must be "dark", which is the default value used in this library. Tailwind requires the class name "dark" for dark-theme.

Use dark-mode specific classes:

<h1 className="text-black dark:text-white">

Please consider enrolling in our courses or sponsoring our work.


with 💖 by Mayank Kumar Chaudhari