Skip to main content
The ThemeProvider component wraps your application to enable theme switching functionality. It must be placed at the root level to make themes available throughout your app.

Installation

The ThemeProvider is automatically included when you install the theme system:
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/nextjs/theme-system.json

Usage

Wrap your application with the ThemeProvider in your root layout:
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 when themes are applied.

Implementation

The ThemeProvider is a thin wrapper around next-themes with pre-configured settings optimized for the tweakcn theme system:
components/theme-provider.tsx
"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 uses the following configuration from next-themes:
attribute
string
default:"data-theme"
The HTML attribute used to apply themes. Sets data-theme="{theme-name}" on the root element.
themes
string[]
default:"allThemeValues"
Array of all available theme values. Automatically generated from your installed themes, including both light and dark variants (e.g., ["default-light", "default-dark", "catppuccin-light", "catppuccin-dark", ...]).
defaultTheme
string
default:"default-dark"
The theme applied on first load before any user selection. Can be customized by importing and using DEFAULT_THEME from @/lib/themes-config.
enableSystem
boolean
default:"false"
System preference detection is disabled because tweakcn themes handle both light and dark modes internally. Each theme exists as separate -light and -dark variants.
disableTransitionOnChange
boolean
default:"true"
Prevents CSS transitions during theme changes to avoid visual flash and improve perceived performance.

Props

children
ReactNode
required
Your application content that will have access to theme functionality.

Theme Values

The provider automatically loads all installed themes from themes-config.ts. Each theme has two variants:
  • {theme-name}-light - Light mode variant
  • {theme-name}-dark - Dark mode variant
Examples:
  • default-dark
  • catppuccin-light
  • cyberpunk-dark
  • vercel-light

Customization

If you need to customize the provider configuration, you can modify the component:
components/theme-provider.tsx
export function ThemeProvider({ children }: { children: ReactNode }) {
  return (
    <NextThemesProvider
      attribute="data-theme"
      themes={allThemeValues}
      defaultTheme="catppuccin-dark" // Custom default theme
      enableSystem={false}
      disableTransitionOnChange={false} // Enable transitions
      storageKey="app-theme" // Custom storage key
    >
      {children}
    </NextThemesProvider>
  );
}
The ThemeProvider must be a client component ("use client"). It uses React context and browser APIs that only work on the client side.

Next.js App Router

For Next.js 13+ with the App Router, place the provider in your root layout:
app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={inter.className}>
        <ThemeProvider>{children}</ThemeProvider>
      </body>
    </html>
  );
}

Vite/React

For Vite or standard React apps, wrap your app in the main entry point:
src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { ThemeProvider } from "./components/theme-provider";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <ThemeProvider>
      <App />
    </ThemeProvider>
  </React.StrictMode>
);

ThemeSwitcher

Add a dropdown UI for selecting themes

useTheme Hook

Control themes programmatically

Build docs developers (and LLMs) love