Quick start
Implement dark mode in three simple steps:ThemeProvider
TheThemeProvider manages theme state, persists user preferences, and handles system theme detection.
Basic usage
Props
List of available theme names.
Default theme name. Use
"system" to respect user’s system preference.Enable system theme detection using
prefers-color-scheme.LocalStorage key for persisting theme preference.
HTML attribute to set on
documentElement. Use "class" for class-based theming.Update the
color-scheme CSS property for native form elements.Disable CSS transitions when switching themes to prevent flash.
Force a specific theme (useful for component previews or documentation).
Style variant affecting border radius and typography.
Accent color for interactive elements.
Gray color variant for neutral elements.
useTheme hook
Access and control the theme programmatically:Return values
Current active theme name (e.g.,
"light", "dark", or "system").Function to update the theme.
The actual rendered theme. If theme is
"system", this returns "light" or "dark" based on system preference.System’s theme preference (only available when
enableSystem is true).List of available theme names.
Forced theme if one is set.
ThemeSwitcher component
A pre-built toggle button for switching between light and dark themes:- Shows a sun icon in dark mode
- Shows a moon icon in light mode
- Toggles between light and dark on click
- Uses Radix UI icons for crisp rendering
Props
Size of the icon in pixels.
Custom theme switcher
Build your own theme switcher using theuseTheme hook:
Multi-theme support
Support more than two themes:Server-side rendering
The ThemeProvider includes a script that prevents theme flashing on page load:<head> that:
- Reads the theme from localStorage
- Detects system preference if theme is “system”
- Applies the theme before React hydrates
- Prevents flash of wrong theme
The
disableTransitionOnChange prop prevents CSS transitions during theme changes, which is especially useful on initial page load.Styling for dark mode
Apsara’s CSS automatically adapts based on thedata-theme attribute:
Best practices
Enable system preference by default
Enable system preference by default
Most users prefer apps that respect their system theme. Set
defaultTheme="system" and enableSystem={true} for the best user experience.Persist user choice
Persist user choice
The default
storageKey saves the theme to localStorage. Users won’t have to reselect their preference on each visit.Test color contrast
Test color contrast
Ensure sufficient contrast in both themes. Aim for WCAG AA compliance (4.5:1 for normal text, 3:1 for large text).
Disable transitions on mount
Disable transitions on mount
Use
disableTransitionOnChange to prevent the flash of animations when the page first loads.Provide visual feedback
Provide visual feedback
Make theme changes obvious with clear visual differences, not just subtle color shifts.
Examples
Next.js app
app/layout.tsx
Vite/React app
main.tsx
Related resources
Theming
Learn about CSS variables and design tokens
Styling
Understand the vanilla CSS approach