> ## 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

> React hook for accessing and controlling theme state from next-themes

## useTheme

React hook provided by `next-themes` for accessing current theme state and controlling theme changes. Used throughout the tweakcn Theme Picker system.

<Note>
  This hook is provided by the [next-themes](https://github.com/pacocoursey/next-themes) library and re-exported from `next-themes`. It must be used within a `ThemeProvider`.
</Note>

## Hook Signature

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

const {
  theme,
  themes,
  setTheme,
  systemTheme,
  resolvedTheme,
  forcedTheme
} = useTheme();
```

## Return Values

<ResponseField name="theme" type="string | undefined">
  The current active theme value (e.g., `"catppuccin-dark"`, `"vercel-light"`).

  Returns `undefined` during SSR or before hydration. Always check for `undefined` or use the mounted pattern.
</ResponseField>

<ResponseField name="setTheme" type="(theme: string) => void">
  Function to change the current theme. Accepts any value from the `themes` array.

  ```typescript theme={null}
  setTheme("catppuccin-dark"); // Switch to Catppuccin dark mode
  ```
</ResponseField>

<ResponseField name="themes" type="string[]">
  Array of all available theme values configured in `ThemeProvider`.

  For tweakcn Theme Picker, this contains all 90 theme variants (45 themes × 2 modes).

  ```typescript theme={null}
  // ["default-light", "default-dark", "catppuccin-light", ...]
  console.log(themes.length); // 90
  ```
</ResponseField>

<ResponseField name="systemTheme" type="'light' | 'dark' | undefined">
  The user's OS-level theme preference (`"light"` or `"dark"`).

  **Not used** in tweakcn Theme Picker since `enableSystem={false}` in the provider.
</ResponseField>

<ResponseField name="resolvedTheme" type="string | undefined">
  The actual theme being used after resolving system preferences.

  In tweakcn, this is the same as `theme` since system theme is disabled.
</ResponseField>

<ResponseField name="forcedTheme" type="string | undefined">
  Theme value if forced by parent component configuration.

  **Not used** in tweakcn Theme Picker.
</ResponseField>

## Basic Usage

### Simple Theme Access

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

function ThemeStatus() {
  const { theme } = useTheme();
  
  return <div>Current theme: {theme}</div>;
}
```

### Theme Switching

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

function ThemeButtons() {
  const { setTheme } = useTheme();
  
  return (
    <div>
      <button onClick={() => setTheme("catppuccin-dark")}>Catppuccin Dark</button>
      <button onClick={() => setTheme("vercel-light")}>Vercel Light</button>
    </div>
  );
}
```

## Advanced Usage

### Hydration-Safe Theme Access

Prevent hydration mismatches by checking if the component has mounted:

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

function SafeThemeDisplay() {
  const [mounted, setMounted] = useState(false);
  const { theme } = useTheme();
  
  useEffect(() => {
    setMounted(true);
  }, []);
  
  if (!mounted) {
    return <div>Loading theme...</div>;
  }
  
  return <div>Current theme: {theme}</div>;
}
```

### Parsing Theme Name and Mode

Extract color theme and mode from the theme string:

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

function parseTheme(theme: string | undefined) {
  if (!theme) return { colorTheme: "default", mode: "dark" };
  
  if (theme.endsWith("-dark")) {
    return { 
      colorTheme: theme.replace("-dark", ""), 
      mode: "dark" as const 
    };
  }
  if (theme.endsWith("-light")) {
    return { 
      colorTheme: theme.replace("-light", ""), 
      mode: "light" as const 
    };
  }
  return { colorTheme: "default", mode: "dark" as const };
}

function ThemeControls() {
  const { theme, setTheme } = useTheme();
  const { colorTheme, mode } = parseTheme(theme);
  
  const toggleMode = () => {
    const newMode = mode === "dark" ? "light" : "dark";
    setTheme(`${colorTheme}-${newMode}`);
  };
  
  const changeColor = (newColor: string) => {
    setTheme(`${newColor}-${mode}`);
  };
  
  return (
    <div>
      <p>Color: {colorTheme}, Mode: {mode}</p>
      <button onClick={toggleMode}>Toggle Mode</button>
      <button onClick={() => changeColor("catppuccin")}>Use Catppuccin</button>
    </div>
  );
}
```

### Theme Validation

Ensure theme values are valid before setting:

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

function SafeThemeSetter() {
  const { setTheme, themes } = useTheme();
  
  const safeSetTheme = (newTheme: string) => {
    if (themes.includes(newTheme)) {
      setTheme(newTheme);
    } else {
      console.error(`Invalid theme: ${newTheme}`);
    }
  };
  
  return (
    <button onClick={() => safeSetTheme("catppuccin-dark")}>
      Switch Theme
    </button>
  );
}
```

### Get Current Theme Configuration

Lookup the full theme config object:

```typescript theme={null}
import { useTheme } from "next-themes";
import { themes, type ThemeConfig } from "@/lib/themes-config";

function ThemeInfo() {
  const { theme } = useTheme();
  
  // Extract color theme name (remove -light/-dark)
  const colorTheme = theme?.replace(/-light|-dark$/, "") || "default";
  
  // Find theme config
  const config = themes.find(t => t.name === colorTheme) || themes[0];
  
  return (
    <div>
      <h3>{config.title}</h3>
      <p>Font: {config.fontSans}</p>
      <div>
        <span>Light: {config.primaryLight}</span>
        <span>Dark: {config.primaryDark}</span>
      </div>
    </div>
  );
}
```

### React to Theme Changes

Run side effects when theme changes:

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

function ThemeLogger() {
  const { theme } = useTheme();
  
  useEffect(() => {
    if (theme) {
      console.log(`Theme changed to: ${theme}`);
      // Analytics, etc.
    }
  }, [theme]);
  
  return null;
}
```

### Programmatic Theme Selection

Cycle through themes or implement custom logic:

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

function ThemeCycler() {
  const { theme, setTheme } = useTheme();
  const { colorTheme, mode } = parseTheme(theme);
  
  const cycleTheme = () => {
    const currentIndex = sortedThemes.findIndex(t => t.name === colorTheme);
    const nextIndex = (currentIndex + 1) % sortedThemes.length;
    const nextTheme = sortedThemes[nextIndex];
    setTheme(`${nextTheme.name}-${mode}`);
  };
  
  return (
    <button onClick={cycleTheme}>
      Next Theme
    </button>
  );
}
```

## Common Patterns

### Theme Persistence

Themes are automatically persisted to `localStorage` by next-themes:

```typescript theme={null}
// Automatically saved
localStorage.getItem("theme"); // "catppuccin-dark"
```

### SSR Considerations

<Warning>
  The `theme` value is `undefined` during SSR. Always handle this case:
</Warning>

```typescript theme={null}
function ThemeDisplay() {
  const { theme } = useTheme();
  
  // ❌ Bad: Can cause hydration mismatch
  return <div>{theme}</div>;
  
  // ✅ Good: Handle undefined
  return <div>{theme || "Loading..."}</div>;
  
  // ✅ Better: Use mounted state (see Hydration-Safe example)
}
```

### Type Safety

Create typed helpers for better autocomplete:

```typescript theme={null}
import { useTheme as useNextTheme } from "next-themes";
import { allThemeValues } from "@/lib/themes-config";

type ThemeValue = typeof allThemeValues[number];

export function useTheme() {
  const { theme, setTheme, ...rest } = useNextTheme();
  
  return {
    theme: theme as ThemeValue | undefined,
    setTheme: (newTheme: ThemeValue) => setTheme(newTheme),
    ...rest
  };
}
```

## Requirements

<Warning>
  This hook MUST be used inside a `ThemeProvider`. Using it outside will throw an error.
</Warning>

```typescript theme={null}
// ❌ Error: useTheme must be used within ThemeProvider
function App() {
  const { theme } = useTheme(); // Error!
  return <div>{theme}</div>;
}

// ✅ Correct: Inside ThemeProvider
function App() {
  return (
    <ThemeProvider>
      <Content />
    </ThemeProvider>
  );
}

function Content() {
  const { theme } = useTheme(); // Works!
  return <div>{theme}</div>;
}
```

## Full Example

Complete implementation using all major features:

```typescript theme={null}
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { themes, sortedThemes } from "@/lib/themes-config";

export function AdvancedThemeControl() {
  const [mounted, setMounted] = useState(false);
  const { theme, setTheme, themes: availableThemes } = useTheme();
  
  useEffect(() => setMounted(true), []);
  
  if (!mounted) {
    return <div className="skeleton" />;
  }
  
  const { colorTheme, mode } = parseTheme(theme);
  const currentConfig = themes.find(t => t.name === colorTheme) || themes[0];
  
  return (
    <div>
      <h2>Theme Control Panel</h2>
      
      {/* Current State */}
      <div>
        <p>Active: {currentConfig.title} ({mode})</p>
        <div style={{ backgroundColor: mode === "dark" ? currentConfig.primaryDark : currentConfig.primaryLight }} />
      </div>
      
      {/* Mode Toggle */}
      <button onClick={() => setTheme(`${colorTheme}-${mode === "dark" ? "light" : "dark"}`)}>
        Toggle to {mode === "dark" ? "Light" : "Dark"}
      </button>
      
      {/* Color Theme Selector */}
      <select 
        value={colorTheme} 
        onChange={(e) => setTheme(`${e.target.value}-${mode}`)}
      >
        {sortedThemes.map(t => (
          <option key={t.name} value={t.name}>
            {t.title}
          </option>
        ))}
      </select>
      
      {/* Stats */}
      <p>Total themes available: {availableThemes.length}</p>
    </div>
  );
}
```

## See Also

* [ThemeProvider](/api/theme-provider) - Required provider setup
* [ThemeSwitcher](/api/theme-switcher) - Pre-built theme picker UI
* [ThemeConfig](/api/theme-config) - Theme object structure
* [next-themes Documentation](https://github.com/pacocoursey/next-themes) - Underlying library docs
