Skip to main content

ThemeProvider

A wrapper around next-themes ThemeProvider that configures theme management for the tweakcn Theme Picker system.
Located in registry/nextjs/components/theme-provider.tsx

Component Signature

export function ThemeProvider({ children }: { children: ReactNode }): JSX.Element

Props

children
ReactNode
required
React children to be wrapped by the theme provider. Typically your entire application tree.

Source Code

"use client";

import { ThemeProvider as NextThemesProvider } from "next-themes";
import { ReactNode } from "react";
import { allThemeValues, DEFAULT_THEME } from "@/lib/themes-config";

export function ThemeProvider({ children }: { children: ReactNode }) {
  return (
    <NextThemesProvider
      attribute="data-theme"
      themes={allThemeValues}
      defaultTheme={DEFAULT_THEME}
      enableSystem={false}
      disableTransitionOnChange
    >
      {children}
    </NextThemesProvider>
  );
}

Configuration

The ThemeProvider is pre-configured with the following settings:

attribute

attribute
string
default:"data-theme"
HTML attribute used to apply the theme. The current theme value is set on the root element as data-theme="theme-name".

themes

themes
string[]
default:"allThemeValues"
Array of all available theme values. Includes both light and dark variants for all 45 themes (90 total values).Examples: ["default-light", "default-dark", "catppuccin-light", "catppuccin-dark", ...]

defaultTheme

defaultTheme
string
default:"default-dark"
Initial theme applied when no user preference exists in localStorage. Set to "default-dark" for a dark-first experience.

enableSystem

enableSystem
boolean
default:false
System theme detection disabled. Users must explicitly choose light or dark mode rather than following OS preferences.

disableTransitionOnChange

disableTransitionOnChange
boolean
default:true
Prevents CSS transitions during theme changes to avoid visual glitches. Theme switches happen instantly.

Usage

App Router (Next.js 13+)

app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
Add suppressHydrationWarning to the <html> tag to prevent hydration warnings from next-themes.

Pages Router (Next.js 12)

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

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

How It Works

  1. Initialization: On mount, the provider reads the theme from localStorage or uses DEFAULT_THEME
  2. DOM Update: The theme value is set as data-theme on the HTML element
  3. Persistence: Theme changes are automatically saved to localStorage
  4. Context: Provides theme state and controls via the useTheme hook

HTML Output

<html lang="en" data-theme="catppuccin-dark">
  <!-- Your app -->
</html>

CSS Integration

Themes are applied using CSS attribute selectors:
globals.css
/* Light mode colors */
[data-theme="catppuccin-light"] {
  --primary: oklch(0.55 0.25 297.02);
}

/* Dark mode colors */
[data-theme="catppuccin-dark"] {
  --primary: oklch(0.79 0.12 304.77);
}

Client-Side Only

This component uses "use client" and must run in the browser. It cannot be used in Server Components directly.
"use client"; // Required for next-themes

Dependencies

  • next-themes: Theme management library (v0.2.1+)
  • React: 18.0.0+
  • Next.js: 13.0.0+ (for App Router) or 12.0.0+ (for Pages Router)

TypeScript Support

Fully typed with TypeScript. The children prop is typed as ReactNode from React.
import { ReactNode } from "react";

export function ThemeProvider({ children }: { children: ReactNode }) {
  // ...
}

See Also

Build docs developers (and LLMs) love