24

Every "add dark mode" prompt gives me pure black backgrounds, #fff text, and one flat gray for everything. It looks like a terminal, not a product, and the contrast is actually too harsh at night.

I turned it into a reusable system prompt that defines tokens semantically (surface, surface-raised, text, text-muted, border, accent) and bakes in real dark-mode craft: slightly desaturated accents, elevation via lightness not shadows, and a minimum contrast target. It generates both themes from one source of truth.

How are people handling accent colors that need to pass contrast on BOTH themes without maintaining two separate palettes?

THE PROMPT
You are a design-systems engineer. Generate a semantic color token set in CSS custom properties supporting light and dark themes from one source of truth.
Rules:
- Tokens are SEMANTIC, never raw: --surface, --surface-raised, --surface-sunken, --text, --text-muted, --border, --accent, --accent-contrast. No component ever references a hex directly.
- Dark theme is the DEFAULT (`:root`), light theme lives under `[data-theme="light"]`.
- Dark mode craft: background is not pure #000 (use ~#0d1117-ish), text is not pure #fff (use ~#e6edf3). Convey elevation by RAISING lightness of surfaces, not by shadow.
- Accents in dark mode must be slightly DESATURATED vs light mode to avoid vibration on dark backgrounds.
- Every text-on-surface pairing must meet WCAG AA (4.5:1 body, 3:1 large). State the computed contrast ratio for --text on --surface and --accent-contrast on --accent.
- Banned: `filter: invert()`, hardcoded shadows for elevation, and a single gray used for both borders and text.
Output the `:root` and `[data-theme="light"]` blocks and a tiny card demo that only uses tokens.
1Semantic tokens with no raw hex in components is the thing that makes theming not a nightmare six months later. Wish more starter templates did this.mobilemuse 2 months ago
add a comment

2 Answers

22

The "elevation via lightness not shadow" rule is exactly right for dark UIs, shadows barely read on near-black. To solve your accent question: define the accent once in OKLCH and derive both themes by only shifting lightness/chroma, keeping hue fixed. Then a single --accent-h drives both. Ask the model to output OKLCH and it'll naturally keep perceptual contrast consistent.

THE PROMPT
Extend: express --accent in `oklch(L C H)`. Keep H constant across themes; dark theme lowers C by ~15% and adjusts L to hit 3:1 against --surface. Derive --accent-contrast as the L that passes 4.5:1 on the accent.
10

One caution: when you desaturate accents for dark mode, double check your success/error/warning colors separately. A desaturated red can drift toward brown and stop reading as "danger". I ask for those three to be validated against their meaning, not just contrast.

Your Answer