DBMS Topics
useTheme
title: "useTheme Hook",
import { Callout } from '../components/Callout' import { PropsTable } from '../components/PropsTable' import { CodeBlock } from '../components/CodeBlock' import { TabGroup, Tab } from '../components/Tabs' import { VersionBadge } from '../components/VersionBadge' import { BreadcrumbNav } from '../components/BreadcrumbNav' import { ApiSignature } from '../components/ApiSignature' import { SeeAlso } from '../components/SeeAlso' import { Playground } from '../components/Playground' import { TypeDefinition } from '../components/TypeDefinition' import { ChangelogEntry } from '../components/ChangelogEntry' import { LinkCard, LinkCardGrid } from '../components/LinkCard'
<BreadcrumbNav items={frontmatter.breadcrumb} />
<VersionBadge version="2.4.0" since="1.0.0" stability="stable" />
This hook gives you full control over theme state — dark mode, light mode, system preference detection, custom themes, CSS variables, and persistent user choices. One hook, everything you need.
npm install @acme/themeAPI Signature
function useTheme(options?: UseThemeOptions): UseThemeReturnParameters
<PropsTable title="UseThemeOptions" props={[ { name: "defaultTheme", type: "'light' | 'dark' | 'system' | string", default: "'system'", required: false, description: "The initial theme to use before user preference is loaded. Falls back to the provider's defaultTheme if not specified." }, { name: "storageKey", type: "string", default: "'acme-theme'", required: false, description: "The localStorage key used to persist the user's theme preference across sessions." }, { name: "enableSystem", type: "boolean", default: "true", required: false, description: "Whether to detect and respond to the operating system's color scheme preference via prefers-color-scheme." }, { name: "enableTransitions", type: "boolean", default: "true", required: false, description: "Whether to apply CSS transitions when switching themes. Set to false for instant theme changes." }, { name: "themes", type: "string[]", default: "['light', 'dark']", required: false, description: "Array of available theme names. Used for validation and by the themes property in the return value." }, { name: "attribute", type: "'class' | 'data-theme' | data-${string}", default: "'class'", required: false, description: "The HTML attribute used to apply the theme to the document element." }, { name: "onThemeChange", type: "(theme: string) => void", default: "undefined", required: false, description: "Callback fired when the theme changes. Useful for analytics or syncing with external systems." }, ]} />
Return Value
Here's what you get back from the hook:
Usage Examples
Basic Theme Toggle
A three-button toggle for light, dark, and system:
Custom Theme with CSS Variables
Want more than just light and dark? Add custom themes like "ocean", "forest", or "sunset":
```tsx title="CustomTheme.tsx" import { useTheme } from '@acme/theme';
export function CustomThemeDemo() { const { resolvedTheme, setTheme, themes } = useTheme({ themes: ['light', 'dark', 'ocean', 'forest', 'sunset'], });
return ( <div className="theme-selector"> {themes.map((t) => ( <button key={t} onClick={() => setTheme(t)} className={swatch swatch-${t}} aria-pressed={resolvedTheme === t} > {t} </button> ))} </div> ); } `` ``css title="themes.css" [data-theme="ocean"] { --color-primary: #0077b6; --color-secondary: #00b4d8; --color-background: #caf0f8; --color-surface: #ffffff; --color-text: #023e8a; }
[data-theme="forest"] { --color-primary: #2d6a4f; --color-secondary: #52b788; --color-background: #d8f3dc; --color-surface: #ffffff; --color-text: #1b4332; }
[data-theme="sunset"] { --color-primary: #e85d04; --color-secondary: #f48c06; --color-background: #fff3e0; --color-surface: #ffffff; --color-text: #6a040f; } `` ``typescript title="theme.config.ts" import { defineThemeConfig } from '@acme/theme';
export const themeConfig = defineThemeConfig({ defaultTheme: 'system', themes: ['light', 'dark', 'ocean', 'forest', 'sunset'], attribute: 'data-theme', storageKey: 'my-app-theme', enableTransitions: true, transitionDuration: 200, cssVariables: { prefix: '--color', mapping: { primary: 'primary', secondary: 'secondary', bg: 'background', surface: 'surface', text: 'text', }, }, }); ```
Server-Side Rendering (SSR)
When using SSR (Next.js, Remix, etc.), the theme can't be determined on the server. Use the isHydrated flag to prevent hydration mismatches, or inject a blocking script using the ThemeScript component.
The trick here is ThemeScript — it runs before React hydrates, so users never see a flash of the wrong theme:
import { ThemeProvider, ThemeScript } from '@acme/theme';
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
{/* Prevents flash of wrong theme */}
<ThemeScript
defaultTheme="system"
storageKey="acme-theme"
attribute="class"
/>
</head>
<body>
<ThemeProvider
defaultTheme="system"
enableSystem={true}
attribute="class"
>
{children}
</ThemeProvider>
</body>
</html>
);
}With React Server Components
Since this hook needs the browser, mark your component with 'use client':
'use client'; // This hook requires client-side JavaScript
import { useTheme } from '@acme/theme';
export function ThemeButton() {
const { toggleTheme, resolvedTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Switch to {resolvedTheme === 'dark' ? 'light' : 'dark'} mode
</button>
);
}Advanced Patterns
Theme-Aware Components
Swap assets based on the current theme. Logos are the classic example:
import { useTheme } from '@acme/theme';
export function Logo() {
const { resolvedTheme } = useTheme();
return (
<img
src={resolvedTheme === 'dark' ? '/logo-light.svg' : '/logo-dark.svg'}
alt="Company Logo"
width={120}
height={40}
/>
);
}Syncing with External Systems
Fire analytics events or update the browser's theme-color meta tag when the theme changes:
TypeScript Support
Full TypeScript definitions ship with the package. If you add custom themes, extend the types:
import '@acme/theme';
declare module '@acme/theme' {
interface ThemeMap {
ocean: true;
forest: true;
sunset: true;
}
}Troubleshooting
This error occurs when useTheme is called in a component that isn't wrapped by ThemeProvider. Ensure your provider is at the root of your component tree. In Next.js, place it in your root layout file.
If you see a flash when the page loads, add the ThemeScript component to your <head>. This injects a small blocking script that sets the theme attribute before React hydrates, eliminating the flash entirely.
| Issue | Cause | Solution |
|---|---|---|
| Flash on page load | Theme determined client-side | Add ThemeScript to <head> |
| Hydration mismatch | Server/client theme differs | Use suppressHydrationWarning |
| Theme not persisting | Storage key conflict | Check storageKey is unique |
| System theme not updating | enableSystem disabled | Set enableSystem: true |
| Transitions not working | CSS transitions missing | Add transition to :root |
Changelog
- Added
forceThemeto return value for preview/demo modes - Added
enableTransitionsoption for smoother theme switches - Fixed hydration issues with React 18 streaming SSR
- Added
onThemeChangecallback option - Improved system theme detection reliability
- Added
isHydratedflag to prevent SSR mismatches
- BREAKING: Renamed
colorModetothemein return value - BREAKING:
ThemeProvidernow requires explicitattributeprop - Added support for unlimited custom themes
- Added
ThemeScriptcomponent for SSR - Dropped support for React 16
See Also
<LinkCard title="ThemeProvider" description="Configure theme settings for your entire application" href="/docs/api/components/theme-provider" icon="component" /> <LinkCard title="ThemeScript" description="Prevent flash of incorrect theme during SSR" href="/docs/api/components/theme-script" icon="code" /> <LinkCard title="CSS Variables Guide" description="Learn how to use CSS variables with the theme system" href="/docs/guides/css-variables" icon="guide" /> <LinkCard title="Dark Mode Tutorial" description="Step-by-step guide to implementing dark mode" href="/docs/tutorials/dark-mode" icon="tutorial" />
export const metadata = { package: "@acme/theme", version: "2.4.0", peerDependencies: { react: ">=18.0.0" }, bundleSize: "1.2kb gzipped", };
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for useTheme.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX topic.
Search Terms
mdx, mdx tutorial, learn mdx, markdown, jsx, tutorial, examples, documentation
Related MDX Topics