> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/BankkRoll/tweakcn-theme-picker/llms.txt
> Use this file to discover all available pages before exploring further.

# useTheme Hook

> Control themes programmatically with the useTheme hook from next-themes

The `useTheme` hook from `next-themes` provides programmatic access to the current theme and methods to change it. Use this hook to build custom theme selectors or implement theme-aware components.

## Installation

The hook is available through `next-themes`, which is automatically installed with the theme system:

```bash theme={null}
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/nextjs/theme-system.json
```

## Basic Usage

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

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

  return (
    <div>
      <p>Current theme: {theme}</p>
      <button onClick={() => setTheme("catppuccin-dark")}>
        Switch to Catppuccin Dark
      </button>
    </div>
  );
}
```

## Return Values

The `useTheme` hook returns an object with the following properties:

<ParamField path="theme" type="string | undefined">
  The current theme value (e.g., `"catppuccin-dark"`, `"vercel-light"`). Will be `undefined` during initial render before hydration.
</ParamField>

<ParamField path="setTheme" type="(theme: string) => void">
  Function to change the current theme. Pass any valid theme value like `"cyberpunk-dark"` or `"nature-light"`.
</ParamField>

<ParamField path="themes" type="string[]">
  Array of all available theme values from the `ThemeProvider`. Contains all installed themes in both light and dark variants.
</ParamField>

<ParamField path="systemTheme" type="'light' | 'dark' | undefined">
  The system's color scheme preference. Always `undefined` in tweakcn theme system because `enableSystem={false}` in the provider.
</ParamField>

<ParamField path="resolvedTheme" type="string | undefined">
  The actual theme being displayed. Same as `theme` in the tweakcn system.
</ParamField>

## Examples

### Get Current Theme

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

export function CurrentThemeDisplay() {
  const { theme } = useTheme();

  return <p>Current theme: {theme}</p>;
}
```

### Switch Theme

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

export function ThemeButton() {
  const { setTheme } = useTheme();

  return (
    <button onClick={() => setTheme("cyberpunk-dark")}>
      Use Cyberpunk Theme
    </button>
  );
}
```

### Toggle Light/Dark Mode

Preserve the color theme while toggling between light and dark:

```tsx theme={null}
import { useTheme } from "next-themes";
import { Moon, Sun } from "lucide-react";

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

  // Parse current theme: "catppuccin-dark" -> "catppuccin"
  const colorTheme = theme?.replace(/-light$|-dark$/, "") || "default";
  const isDark = theme?.endsWith("-dark") ?? true;

  const toggleMode = () => {
    const newMode = isDark ? "light" : "dark";
    setTheme(`${colorTheme}-${newMode}`);
  };

  return (
    <button onClick={toggleMode}>
      {isDark ? <Moon /> : <Sun />}
      {isDark ? "Dark" : "Light"} Mode
    </button>
  );
}
```

### List All Available Themes

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

export function ThemeList() {
  const { themes } = useTheme();

  return (
    <ul>
      {themes.map((themeName) => (
        <li key={themeName}>{themeName}</li>
      ))}
    </ul>
  );
}
```

### Simple Theme Selector

Create a basic dropdown selector:

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

export function SimpleThemeSelector() {
  const { theme, setTheme, themes } = useTheme();

  return (
    <select value={theme} onChange={(e) => setTheme(e.target.value)}>
      {themes.map((themeName) => (
        <option key={themeName} value={themeName}>
          {themeName}
        </option>
      ))}
    </select>
  );
}
```

### Theme-Aware Component

Conditionally render based on the current theme:

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

export function BrandLogo() {
  const { theme } = useTheme();
  const isDark = theme?.endsWith("-dark");

  return (
    <img
      src={isDark ? "/logo-dark.svg" : "/logo-light.svg"}
      alt="Logo"
    />
  );
}
```

### Parse Theme Components

Extract theme name and mode from the theme string:

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

function parseTheme(theme: string | undefined) {
  if (!theme) return { name: "default", mode: "dark" };

  if (theme.endsWith("-dark")) {
    return { name: theme.replace("-dark", ""), mode: "dark" as const };
  }
  if (theme.endsWith("-light")) {
    return { name: theme.replace("-light", ""), mode: "light" as const };
  }
  return { name: "default", mode: "dark" as const };
}

export function ThemeInfo() {
  const { theme } = useTheme();
  const { name, mode } = parseTheme(theme);

  return (
    <div>
      <p>Theme: {name}</p>
      <p>Mode: {mode}</p>
    </div>
  );
}
```

### Switch Color Theme (Preserve Mode)

Change the color theme while keeping the current light/dark mode:

```tsx theme={null}
import { useTheme } from "next-themes";
import { themes } from "@/lib/themes-config";

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

  // Extract current mode
  const currentMode = theme?.endsWith("-dark") ? "dark" : "light";

  const handleThemeChange = (themeName: string) => {
    setTheme(`${themeName}-${currentMode}`);
  };

  return (
    <div>
      {themes.map((t) => (
        <button key={t.name} onClick={() => handleThemeChange(t.name)}>
          {t.title}
        </button>
      ))}
    </div>
  );
}
```

### Theme Persistence

Theme selection is automatically persisted to `localStorage` by `next-themes`. The stored value persists across browser sessions:

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

export function ThemeStatus() {
  const { theme } = useTheme();

  // Check localStorage (client-side only)
  const storedTheme = typeof window !== "undefined" 
    ? localStorage.getItem("theme")
    : null;

  return (
    <div>
      <p>Current: {theme}</p>
      <p>Stored: {storedTheme}</p>
    </div>
  );
}
```

## Hydration Handling

The `theme` value is `undefined` during server-side rendering and initial client render. Always handle this case:

```tsx theme={null}
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";

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

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

  if (!mounted) {
    return <div>Loading...</div>;
  }

  return <div>Current theme: {theme}</div>;
}
```

Or use optional chaining:

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

export function ThemeDisplay() {
  const { theme } = useTheme();

  return <div>Current theme: {theme ?? "loading..."}</div>;
}
```

## Theme Naming Convention

All tweakcn themes follow the pattern `{name}-{mode}`:

```tsx theme={null}
// Valid theme values:
"default-light"      // ✓
"default-dark"       // ✓
"catppuccin-light"   // ✓
"cyberpunk-dark"     // ✓

// Invalid (will not work):
"default"            // ✗ Missing mode
"catppuccin"         // ✗ Missing mode
"dark"               // ✗ Missing name
```

When building custom selectors, always include both the theme name and mode:

```tsx theme={null}
setTheme(`${themeName}-${mode}`); // ✓ Correct
setTheme(themeName);               // ✗ Incorrect
```

## Using with Theme Config

Combine with `themes-config.ts` for rich theme metadata:

```tsx theme={null}
import { useTheme } from "next-themes";
import { themes } from "@/lib/themes-config";

export function ThemePreview() {
  const { theme, setTheme } = useTheme();
  const currentMode = theme?.endsWith("-dark") ? "dark" : "light";

  return (
    <div className="grid grid-cols-3 gap-4">
      {themes.map((t) => (
        <button
          key={t.name}
          onClick={() => setTheme(`${t.name}-${currentMode}`)}
          className="flex items-center gap-2 p-3 border rounded-lg"
        >
          <div
            className="h-6 w-6 rounded-full"
            style={{
              backgroundColor:
                currentMode === "dark" ? t.primaryDark : t.primaryLight,
            }}
          />
          <div className="text-left">
            <p className="font-medium">{t.title}</p>
            <p className="text-xs text-muted-foreground">{t.fontSans}</p>
          </div>
        </button>
      ))}
    </div>
  );
}
```

## Next.js Server Components

The `useTheme` hook only works in Client Components. Mark your component with `"use client"`:

```tsx theme={null}
"use client";

import { useTheme } from "next-themes";

export function ClientThemeComponent() {
  const { theme, setTheme } = useTheme();
  // ...
}
```

If you need theme data in Server Components, access it via cookies (advanced):

```tsx theme={null}
import { cookies } from "next/headers";

export function ServerThemeComponent() {
  const theme = cookies().get("theme")?.value ?? "default-dark";
  // Server-side theme access (read-only)
}
```

<Note>
  Server-side theme access is read-only. Use client components with `useTheme` for interactive theme switching.
</Note>

## Related

<CardGroup cols={2}>
  <Card title="ThemeSwitcher" icon="palette" href="/usage/theme-switcher">
    Pre-built theme selector component
  </Card>

  <Card title="Custom Selector" icon="wand-magic-sparkles" href="/usage/custom-theme-selector">
    Build your own theme selector
  </Card>
</CardGroup>
