# How to Configure the ThemeProvider with next-themes for Dark Mode in Refine-ShadCN

> Learn to easily configure ThemeProvider with next-themes for dark mode in Refine-ShadCN. Set defaultTheme dark and enableSystem for seamless OS integration. Improve user experience now.

- Repository: [Ferdi ÜNAL/refine-shadcn](https://github.com/ferdiunal/refine-shadcn)
- Tags: how-to-guide
- Published: 2026-03-01

---

**To enable dark mode in Refine-ShadCN, wrap your application with the `ThemeProvider` exported from `@ferdiunal/refine-shadcn`, set `defaultTheme="dark"`, and keep `enableSystem={true}` to respect the user's OS preference.**

Refine-ShadCN (`ferdiunal/refine-shadcn`) ships a thin wrapper around the **next-themes** library that handles all theme state management. Because the `ThemeProvider` component in [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx) simply forwards every prop to the underlying `NextThemesProvider`, you configure dark mode using the standard next-themes API.

## How the ThemeProvider Works

The `ThemeProvider` is a client-side wrapper that re-exports `next-themes` without modification. Located at [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx), it accepts the complete `ThemeProviderProps` interface from next-themes and passes them directly to the provider:

```tsx
// packages/theme/src/providers/theme-provider.tsx
"use client";

import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes";

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
    return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

```

This architecture means any configuration valid for `next-themes` is valid for Refine-ShadCN's wrapper.

## Configuring Dark Mode in Your Layout

For a Next.js App Router application, import the provider in your root layout and configure the dark mode defaults. The following example initializes the app in dark mode while still allowing system preference detection:

```tsx
// app/layout.tsx
import "./globals.css";
import { ThemeProvider } from "@ferdiunal/refine-shadcn";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="dark"
          enableSystem={true}
          disableTransitionOnChange={false}
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

```

Set `attribute="class"` to apply themes via CSS classes (required for Tailwind's dark mode strategy), and `defaultTheme="dark"` to render the dark theme on first load before hydration.

### Key Configuration Properties

The `ThemeProvider` accepts all standard next-themes properties. For dark mode configuration, these are the most critical:

- **`defaultTheme`**: Sets the initial theme value. Use `"dark"` for dark-first applications, `"system"` to follow the OS, or `"light"` for light-first.
- **`enableSystem`**: Boolean that allows the operating system preference to override `defaultTheme`. Keep this `true` to respect user system settings.
- **`attribute`**: The HTML attribute to apply the theme class. Use `"class"` (default) for Tailwind CSS integration or `"data-theme"` for CSS variable scoping.
- **`disableTransitionOnChange`**: Set to `true` to disable CSS transitions during theme switches, preventing color flash during hydration.
- **`forcedTheme`**: Optional string to force a specific theme regardless of user preference, useful for embedded previews or marketing pages.

## Using BaseLayout for Automatic Provider Injection

If you prefer a batteries-included approach, import the `BaseLayout` component from [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx). This layout automatically wraps children with `ThemeProvider` and includes additional UI wrappers like `TooltipProvider` and `Toaster`.

```tsx
import { BaseLayout } from "@ferdiunal/refine-shadcn";

export default function Layout({ children }) {
  return (
    <BaseLayout
      defaultTheme="dark"
      enableSystem={true}
      attribute="class"
    >
      {children}
    </BaseLayout>
  );
}

```

The `BaseLayout` forwards all theme-related props to the underlying `ThemeProvider`, so the configuration API remains identical.

## Adding User Controls with ModeToggle

Refine-ShadCN includes a pre-built toggle component located at [`packages/theme/src/components/modeToggle.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/components/modeToggle.tsx). This component renders a dropdown menu allowing users to switch between **light**, **dark**, and **system** modes:

```tsx
import { ModeToggle } from "@ferdiunal/refine-shadcn";

export function Header() {
  return (
    <header className="flex justify-end p-4">
      <ModeToggle />
    </header>
  );
}

```

The `ModeToggle` uses the `useTheme` hook from `next-themes` internally to read and update the current theme state.

## Controlling Themes Programmatically

For custom UI elements or settings pages, access the theme state directly using the `useTheme` hook from `next-themes`:

```tsx
import { useTheme } from "next-themes";

function ThemeSettings() {
  const { theme, setTheme, resolvedTheme } = useTheme();

  const enableDarkMode = () => setTheme("dark");
  const enableLightMode = () => setTheme("light");
  const resetToSystem = () => setTheme("system");

  return (
    <div>
      <p>Current theme: {resolvedTheme}</p>
      <button onClick={enableDarkMode}>Force Dark</button>
      <button onClick={enableLightMode}>Force Light</button>
    </div>
  );
}

```

The `resolvedTheme` property returns the actual applied theme (resolving `"system"` to either `"light"` or `"dark"`), while `theme` returns the raw stored value.

## Summary

- **Import `ThemeProvider`** from `@ferdiunal/refine-shadcn` (located at [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx)) to wrap your application root.
- **Set `defaultTheme="dark"`** and **`enableSystem={true}`** to initialize with dark mode while respecting OS preferences.
- **Use `BaseLayout`** from [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx) for a pre-configured layout that includes the provider and additional UI utilities.
- **Drop in `ModeToggle`** from [`packages/theme/src/components/modeToggle.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/components/modeToggle.tsx) to give users manual control over the color scheme.
- **Access `useTheme`** from `next-themes` directly for programmatic theme manipulation in custom components.

## Frequently Asked Questions

### Does Refine-ShadCN use a custom theming engine or next-themes?

Refine-ShadCN uses a thin wrapper around next-themes. The `ThemeProvider` in [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx) simply re-exports `NextThemesProvider` and forwards all props unchanged, so the configuration API is identical to the standard next-themes library.

### How do I prevent the white flash during page load in dark mode?

Set `disableTransitionOnChange={true}` on the `ThemeProvider`. This disables CSS transitions during the theme switch that happens on hydration, preventing the brief flash of unstyled content. Ensure your CSS framework (like Tailwind) is configured to use class-based dark mode with the `"class"` attribute.

### Can I force a specific theme on certain pages while keeping global settings elsewhere?

Yes. Pass the `forcedTheme` prop to the `ThemeProvider` or `BaseLayout` on specific layouts or pages. This overrides both the `defaultTheme` and user preferences for that specific component tree, which is useful for landing pages or embedded dashboards that must display in a fixed color scheme.

### Where is the user's theme preference stored?

By default, next-themes persists the selected theme in `localStorage` under the key `theme`. You can customize the storage key using the `storageKey` prop on the `ThemeProvider`, or disable persistence by handling theme state externally and passing controlled props.