Dark Mode
Add light and dark mode to your app.
Appica UI is dark-mode-ready out of the box. The token system ships both a light
and a dark palette; switching themes is a matter of toggling a class on the
<html> element, which ThemeProvider manages for
you — including persistence and a no-flash first paint.
How it works
Dark mode is class-based. When the dark class is on a <html> ancestor,
the dark token values apply. The library defines the variant as:
So you can write dark-only utilities in your own markup too:
Setup
Wrap your app in ThemeProvider at your app's root (covered in
Installation). It applies the correct class before
the page paints, so there's no flash of the wrong theme on load. The example
uses Next.js's root layout — see the
Framework notes for where this file
lives in Vite, React Router / Remix, TanStack Start, and Astro:
suppressHydrationWarning on <html> is expected: the no-flash script sets the theme class before React
hydrates, so the server and client markup intentionally differ by that one attribute.
By default ThemeProvider follows the OS preference (enableSystem) and persists
the user's choice under the theme key in localStorage.
Building a theme toggle
Read and set the theme with useTheme. Guard
theme-dependent UI with mounted so the server-rendered output matches the first
client render:
themeis the stored choice, which may be'system'.resolvedThemeis what's actually applied —'system'resolved to'light'or'dark'.systemThemeis the current OS preference.
Common options
ThemeProvider accepts several props to tune behavior:
To force a single theme on a specific route, nest another provider with
forcedTheme:
See ThemeProvider for the full prop reference and
useTheme for the hook.