better-themes
Frameworks

Next.js Pages Router

Setup guide for Next.js Pages Router

Installation

npm install better-themes

Setup

Update _app.tsx

Wrap your app with ThemeProvider in pages/_app.tsx:

pages/_app.tsx
import { ThemeProvider } from "better-themes";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider attribute="class" disableTransitionOnChange>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

Update _document.tsx

Add suppressHydrationWarning to your <html> tag:

pages/_document.tsx
import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
  return (
    <Html lang="en" suppressHydrationWarning>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

Create a theme switcher component

components/theme-switcher.tsx
import { useTheme } from "better-themes";
import { useEffect, useState } from "react";

export function ThemeSwitcher() {
  const [mounted, setMounted] = useState(false);
  const { theme, setTheme } = useTheme();

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

  if (!mounted) {
    return null;
  }

  return (
    <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
      Toggle theme
    </button>
  );
}

Tailwind CSS Configuration

If you're using Tailwind CSS, configure it for class-based dark mode:

tailwind.config.js
export default {
  darkMode: ["class"],
  // ... rest of config
};

Complete Example

pages/_app.tsx
import { ThemeProvider } from "better-themes";
import type { AppProps } from "next/app";
import { ThemeSwitcher } from "@/components/theme-switcher";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider attribute="class" disableTransitionOnChange>
      <ThemeSwitcher />
      <Component {...pageProps} />
    </ThemeProvider>
  );
}
pages/_document.tsx
import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
  return (
    <Html lang="en" suppressHydrationWarning>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

Notes

  • Use the default export (not /rsc) for Next.js Pages Router
  • Add suppressHydrationWarning to the <Html> component in _document.tsx

Example

View a complete example implementation: Next.js Pages Router Example

Try the live demo: Live Demo

On this page