What this prompt does
This prompt implements a complete dark mode system for a [framework] app with [component_count] components, built on CSS custom properties rather than scattered overrides. It starts with a semantic token architecture, mapping abstract names like --color-surface and --color-text-primary to concrete values, then derives a proper dark palette, wires up the toggle, handles images and transitions, and ends with a [component_framework] ThemeProvider. Building from semantic tokens means switching themes is a single source change, not a hunt through every component.
The variables encode the quality details that separate a real implementation from a hack. [token_count] sets how granular the token layer is, and [dark_selector] decides the activation strategy. Crucially, the prompt does not invert colors: [dark_surface_color], [dark_contrast_target], and [desaturation_amount] shape a comfortable dark palette. [toggle_approach] and [storage_method] handle the three-state light/dark/system choice and persistence, and the prompt explicitly applies the theme before first paint to kill the flash of wrong theme.
When to use it
- Adding dark mode to an app that currently only ships a
[current_theme]light theme. - Replacing a naive color-inversion hack with a proper desaturated dark palette.
- Building a three-state toggle that respects manual choice, then system preference, then default.
- Eliminating the flash of wrong theme on first paint with SSR-safe persistence.
- Establishing a reusable semantic token layer across many components.
- Handling images, logos, and SVG icons correctly in dark mode instead of dimming everything.
Example output
You get an implementation plan with code: a set of [token_count] CSS custom properties defined in :root and your [dark_selector], a derived dark palette using [dark_surface_color] with text at [dark_contrast_target] and vivid colors desaturated by [desaturation_amount], a toggle using [toggle_approach] persisting to [storage_method] with a pre-paint script, image and media strategies, [transition_duration] transitions on color properties (excluded on load), a validation checklist covering focus rings and autofill, and a ThemeProvider exposing a useTheme() hook.
Pro tips
- Keep the token layer semantic; name tokens by role (
--color-surface) not by value, so dark mode is a remap rather than a rewrite. - Use a near-black like the
[dark_surface_color]default rather than pure#000; pure black creates harsh contrast and halo effects. - Tune
[desaturation_amount]to taste; vivid brand colors that look great on white often glare on dark surfaces. - Apply the theme before first paint via an inline script; this is the single most important step for avoiding the flash.
- Verify the
[dark_contrast_target]against real text, especially secondary and muted tones, which are easy to push too dim. - Exclude code blocks and photos from the
[transition_duration]transition so they do not flicker awkwardly during the switch. - Walk the validation checklist for focus rings, selection colors, scrollbars, and autofill backgrounds; these are the spots a dark theme quietly breaks.