Dark mode
Also called dark theme or night mode
An alternate color theme with light text on dark backgrounds, chosen in settings or matched to the device’s system setting.
import { useEffect, useState } from 'react';
import { Toggle } from '@base-ui/react/toggle';
import { ToggleGroup } from '@base-ui/react/toggle-group';
const THEMES = ['light', 'dark', 'system'] as const;
type Theme = (typeof THEMES)[number];
const DARK_QUERY = '(prefers-color-scheme: dark)';
// Theme tokens such as bg-background switch under .dark on <html>. Run the
// same code in an inline <head> script too, so the first paint is right.
function applyTheme(theme: Theme) {
const dark =
theme === 'dark' || (theme === 'system' && matchMedia(DARK_QUERY).matches);
document.documentElement.classList.toggle('dark', dark);
document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
}
export function ThemePicker() {
const [theme, setTheme] = useState<Theme>(
() => THEMES.find((t) => t === localStorage.getItem('theme')) ?? 'system'
);
useEffect(() => {
applyTheme(theme);
localStorage.setItem('theme', theme);
if (theme !== 'system') return;
// Follow the device setting while System is selected.
const media = matchMedia(DARK_QUERY);
const onChange = () => applyTheme('system');
media.addEventListener('change', onChange);
return () => media.removeEventListener('change', onChange);
}, [theme]);
return (
<ToggleGroup
aria-label='Theme'
value={[theme]}
onValueChange={(value) => {
const next = THEMES.find((t) => t === value[0]);
if (next) setTheme(next); // ignore clicks on the selected option
}}
className='inline-flex gap-1 rounded-full border bg-muted p-1'
>
{THEMES.map((option) => (
<Toggle
key={option}
value={option}
className='rounded-full px-3 py-1.5 text-sm text-muted-foreground capitalize data-pressed:bg-background data-pressed:text-foreground data-pressed:shadow-sm focus-visible:outline-2 focus-visible:outline-blue-500'
>
{option}
</Toggle>
))}
</ToggleGroup>
);
}Add dark mode with Light, Dark, and System options in settings. Define every color as a CSS variable, override them under a .dark class on <html>, default to System with prefers-color-scheme, and save the choice in localStorage. Apply the saved theme with an inline script in <head> so there is no white flash, set color-scheme to match, and use #0a0a0a instead of pure black for the page background.
Paste into Layerwise or any AI coding tool.
What is Dark mode?
Dark mode swaps an interface’s light backgrounds for dark ones and flips text to light colors, while the layout stays the same. Most apps offer three choices: Light, Dark, and System, which follows the device setting through the prefers-color-scheme media query.
Build it with color variables instead of fixed colors: define tokens such as --background and --text, then give them new values under a .dark class or a data-theme="dark" attribute on the root element. Every component that uses the tokens switches at once. Set color-scheme too, so scrollbars and form controls match.
Good dark mode takes more than inverted colors. Use dark gray rather than pure black, tone down bright accent colors, show depth with lighter surfaces instead of shadows, and check text contrast again in both themes. Apply the saved theme before the page paints, or visitors see a white flash on load. For a circular reveal like the demo’s, the View Transitions API with an animated clip-path does the job.
Related terms
All termsColor contrast
How much text stands out from its background, measured as a ratio from 1:1 to 21:1 and checked against the WCAG levels AA and AAA.
Accent color
The one highlight color an interface uses for actions and selected states, and the CSS property that tints native form controls.
View Transitions API
A browser feature that animates between two states of a page by snapshotting the old view, applying your update, and animating to the new one.
Clip-path
A CSS property that cuts an element to a shape, such as a circle, an inset rectangle, or a polygon, and hides everything outside it.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.