> ## Documentation Index
> Fetch the complete documentation index at: https://subframe-59800133-gtmbot-restructure-dark-mode-docs-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Dark mode toggle

> Add a dark mode toggle to your app using Subframe's generated theme.

When you [enable dark mode](/learn/theme/dark-mode) in your theme, the CLI generates your color tokens as CSS variables instead of hardcoded values. Light mode values load by default, and dark mode values activate when a `dark` class is present on the page. This guide covers how to toggle between them.

## How the generated code works

<Tabs>
  <Tab title="Tailwind v3">
    The CLI syncs two files:

    * **`tailwind.config.js`** — references CSS variables instead of hardcoded values, with `darkMode: 'selector'` enabled
    * **`theme.css`** — defines `:root` variables for light mode and `.dark` overrides for dark mode

    ```js tailwind.config.js theme={null}
    module.exports = {
      darkMode: 'selector',
      theme: {
        extend: {
          colors: {
            "brand-primary": "rgb(var(--color-brand-primary) / <alpha-value>)",
            // ... all color tokens as CSS variable references
          },
        },
      },
    }
    ```

    ```css theme.css theme={null}
    :root {
      --color-brand-primary: 26 26 26;
      --color-default-background: 252 252 252;
      /* ... light mode values */
    }

    .dark {
      --color-brand-primary: 212 212 212;
      --color-default-background: 10 10 10;
      /* ... dark mode overrides */
    }
    ```

    Import `theme.css` in your global stylesheet or entry point:

    ```css globals.css theme={null}
    @import "./subframe/theme.css";
    ```
  </Tab>

  <Tab title="Tailwind v4">
    The generated `theme.css` includes a `@custom-variant` for dark mode and a `.dark` block with overrides:

    ```css theme.css theme={null}
    @custom-variant dark (&:where(.dark, .dark *));

    @theme {
      --color-brand-primary: rgb(26 26 26);
      --color-default-background: rgb(252 252 252);
      /* ... light mode values */
    }

    .dark {
      --color-brand-primary: rgb(212 212 212);
      --color-default-background: rgb(10 10 10);
      /* ... dark mode overrides */
    }
    ```
  </Tab>
</Tabs>

## Sync your theme

Run the CLI to sync your theme (including dark mode) to your codebase:

<CodeGroup>
  ```bash npm theme={null}
  npx @subframe/cli@latest sync --all
  ```

  ```bash yarn theme={null}
  yarn dlx @subframe/cli@latest sync --all
  ```

  ```bash pnpm theme={null}
  pnpx @subframe/cli@latest sync --all
  ```

  ```bash bun theme={null}
  bunx @subframe/cli@latest sync --all
  ```
</CodeGroup>

## Add a toggle

To switch between light and dark mode, your app needs to toggle the `dark` class on the `<html>` element. Here's how to set that up:

<Tabs>
  <Tab title="Next.js (next-themes)">
    <Steps>
      <Step title="Install next-themes">
        ```bash theme={null}
        npm install next-themes
        ```
      </Step>

      <Step title="Wrap your app in the ThemeProvider">
        ```tsx app/layout.tsx theme={null}
        import { ThemeProvider } from "next-themes"

        export default function RootLayout({ children }) {
          return (
            <html suppressHydrationWarning>
              <body>
                <ThemeProvider attribute="class" defaultTheme="system">
                  {children}
                </ThemeProvider>
              </body>
            </html>
          )
        }
        ```
      </Step>

      <Step title="Add a toggle button">
        ```tsx theme={null}
        import { useTheme } from "next-themes"

        export function ThemeToggle() {
          const { theme, setTheme } = useTheme()

          return (
            <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
              {theme === "dark" ? "Light mode" : "Dark mode"}
            </button>
          )
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Vite / React">
    <Steps>
      <Step title="Create a ThemeProvider">
        ```tsx ThemeProvider.tsx theme={null}
        import { createContext, useContext, useEffect, useState } from "react"

        const ThemeContext = createContext({ theme: "light", toggleTheme: () => {} })

        export function ThemeProvider({ children }) {
          const [theme, setTheme] = useState(() => {
            if (typeof window !== "undefined") {
              return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
            }
            return "light"
          })

          useEffect(() => {
            document.documentElement.classList.remove("light", "dark")
            document.documentElement.classList.add(theme)
          }, [theme])

          const toggleTheme = () => setTheme(theme === "light" ? "dark" : "light")

          return <ThemeContext.Provider value=undefined>{children}</ThemeContext.Provider>
        }

        export const useTheme = () => useContext(ThemeContext)
        ```
      </Step>

      <Step title="Wrap your app">
        ```tsx main.tsx theme={null}
        import { ThemeProvider } from "./ThemeProvider"

        ReactDOM.createRoot(document.getElementById("root")!).render(
          <ThemeProvider>
            <App />
          </ThemeProvider>
        )
        ```
      </Step>

      <Step title="Add a toggle button">
        ```tsx theme={null}
        import { useTheme } from "./ThemeProvider"

        export function ThemeToggle() {
          const { theme, toggleTheme } = useTheme()

          return (
            <button onClick={toggleTheme}>
              {theme === "dark" ? "Light mode" : "Dark mode"}
            </button>
          )
        }
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>
