Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,106 @@ Now set the `attribute` for your ThemeProvider to `data-mode`:

With this setup, you can now use Tailwind's dark mode classes, as in the previous example.

### Custom Theming

While `tanstack-theme-kit` defaults to `light` and `dark` themes, you can easily define and switch between any number of custom themes. This is particularly useful for brand-specific themes, high-contrast modes, or seasonal themes.

#### 1. Define your custom themes in CSS

Create CSS variables for each theme and apply them based on the `data-theme` attribute (or `class` if you're using Tailwind):

```css
/* Default / Light theme */
:root {
--background: #ffffff;
--foreground: #000000;
--accent: #3b82f6;
}

/* Dark theme */
[data-theme='dark'] {
--background: #000000;
--foreground: #ffffff;
--accent: #60a5fa;
}

/* Custom 'ocean' theme */
[data-theme='ocean'] {
--background: #0f172a;
--foreground: #e2e8f0;
--accent: #06b6d4;
}

/* Custom 'forest' theme */
[data-theme='forest'] {
--background: #064e3b;
--foreground: #ecfdf5;
--accent: #10b981;
}
```

#### 2. Configure the ThemeProvider

Pass your custom theme names to the `themes` prop. If you want to keep the default `light` and `dark` themes alongside your custom ones, include them in the array:

```tsx
import { ThemeProvider } from 'tanstack-theme-kit'

function App() {
return (
<ThemeProvider
themes={['light', 'dark', 'ocean', 'forest']}
defaultTheme="light"
enableSystem={true}
>
{/* Your app content */}
</ThemeProvider>
)
}
```

> **Note:** Themes are automatically persisted in `localStorage` using the `storageKey` prop (default: `'theme'`). Users' theme selections will survive page refreshes and sessions out of the box.

#### 3. Create a theme switcher

Use the `useTheme` hook to build a UI component that allows users to switch between your custom themes:

```tsx
import { useState, useEffect } from 'react'
import { useTheme } from 'tanstack-theme-kit'

const themes = ['light', 'dark', 'ocean', 'forest']

export default function ThemeSwitcher() {
const [mounted, setMounted] = useState(false)
const { theme, setTheme } = useTheme()

// Prevent hydration mismatch
useEffect(() => setMounted(true), [])

if (!mounted) return null

return (
<div className="theme-switcher">
<label htmlFor="theme-select">Choose a theme: </label>
<select
id="theme-select"
value={theme}
onChange={(e) => setTheme(e.target.value)}
>
{themes.map((t) => (
<option key={t} value={t}>
{t.charAt(0).toUpperCase() + t.slice(1)}
</option>
))}
</select>
</div>
)
}
```

With this setup, selecting a theme from the dropdown will instantly update the `data-theme` attribute on the `<html>` element, applying your custom CSS variables without any flash or hydration errors.

## Discussion

### The Flash
Expand Down