Web Theme
Purpose
Plan light/dark (and any brand) themes as token-value swaps over the web-design-system foundation: detection of system preference, a persisted manual override, and a render path that avoids the wrong-theme flash on server-rendered apps.
When to Use
- After tokens exist, when the product needs light/dark or multiple brands.
- When theme flicker, mixed hardcoded colors, or failing dark-mode contrast appear in an existing app.
- Not before
web-design-system has defined semantic tokens.
Inputs
- Semantic tokens from
web-design-system.
- Framework foundation (SSR vs SPA changes the flash-avoidance strategy).
- Requirement: system-follow only, manual toggle, or both.
Discovery Questions
- Follow
prefers-color-scheme, offer a manual toggle, or both (typical: both, override persisted)?
- Where is the preference persisted (localStorage, cookie) — and does SSR need it server-side to render correctly?
- Are there more themes than light/dark (brands, high-contrast)?
- Do embedded surfaces (emails, charts, iframes) need theme values too?
Responsibilities
- Define theme layers: semantic tokens resolve to per-theme values (CSS variables are the usual mechanism).
- Plan detection + override: default to system preference; manual choice wins and persists.
- Plan flash avoidance: on Next.js, set the theme attribute before first paint (inline script or cookie-driven server render); on a Vite SPA, apply before mount.
- Require contrast validation in both themes (
web-accessibility) — dark mode is a first-class theme, not an inversion filter.
- Cover non-component surfaces: charts (
dashboard-reporting), scrollbars, meta color-scheme, favicons where relevant.
Required Workflow
- Confirm token readiness; list themes required.
- Choose the persistence + detection mechanism (SSR-aware if Next.js).
- Define per-theme token values; validate contrast in each.
- Plan the switch UX (toggle placement, no layout shift).
- Record the plan; hand chart/table theming notes to the dashboard skills.
Decision Rules
- Components consume semantic tokens only; a theme is a token-value set, never per-component conditionals.
- Manual override beats system preference; absence of override follows the system live.
- If SSR renders themed markup, the server must know the preference (cookie) — otherwise render neutral and set it pre-paint.
- Don't add a theming abstraction for a single fixed theme; note the extension point and stop.
Rules
- No hardcoded colors outside token definitions.
- Both themes ship accessible or the second theme doesn't ship.
- Theme switching must not trigger layout shift or content reflow.
Anti-Patterns
- Dark mode via
filter: invert() or ad-hoc dark: overrides scattered without token discipline.
- Theme state in a global store re-rendering the world on toggle instead of a root attribute + CSS variables.
- Shipping dark mode that fails contrast because only light was checked.
- SSR pages that flash light-then-dark on every load.
Validation Checklist
Definition of Done
A recorded theming plan — themes, token values, detection/persistence, flash avoidance, and contrast validation — where switching themes changes token values only and both themes meet accessibility standards.
Related Skills
web-design-system, web-accessibility, nextjs-foundation, vite-react-foundation, dashboard-reporting.
Related Knowledge
../../../knowledge/ (brand palette decisions).
Related References
../../../references/web/design-system/ (theme token tables — when populated).
Context Loading Guidance
- Requires: semantic tokens, framework foundation, theme requirements.
- Does not require: full component inventory, data-layer detail.
- May load:
web-accessibility for contrast criteria.
- Stop when: the theming plan is recorded.
Token Efficiency Guidance
Represent themes as token-value tables. Don't enumerate component-by-component styling — the token layer makes that unnecessary.
1---2name: web-theme3description: Use to plan light/dark theming on top of design tokens — system preference detection, manual override with persistence, SSR flash avoidance on Next.js, and contrast validation in both themes. Themes switch token values; components never hardcode colors.4---56# Web Theme78## Purpose910Plan light/dark (and any brand) themes as token-value swaps over the `web-design-system` foundation: detection of system preference, a persisted manual override, and a render path that avoids the wrong-theme flash on server-rendered apps.1112## When to Use1314- After tokens exist, when the product needs light/dark or multiple brands.15- When theme flicker, mixed hardcoded colors, or failing dark-mode contrast appear in an existing app.16- **Not** before `web-design-system` has defined semantic tokens.1718## Inputs1920- Semantic tokens from `web-design-system`.21- Framework foundation (SSR vs SPA changes the flash-avoidance strategy).22- Requirement: system-follow only, manual toggle, or both.2324## Discovery Questions2526- Follow `prefers-color-scheme`, offer a manual toggle, or both (typical: both, override persisted)?27- Where is the preference persisted (localStorage, cookie) — and does SSR need it server-side to render correctly?28- Are there more themes than light/dark (brands, high-contrast)?29- Do embedded surfaces (emails, charts, iframes) need theme values too?3031## Responsibilities3233- Define **theme layers**: semantic tokens resolve to per-theme values (CSS variables are the usual mechanism).34- Plan **detection + override**: default to system preference; manual choice wins and persists.35- Plan **flash avoidance**: on Next.js, set the theme attribute before first paint (inline script or cookie-driven server render); on a Vite SPA, apply before mount.36- Require **contrast validation in both themes** (`web-accessibility`) — dark mode is a first-class theme, not an inversion filter.37- Cover non-component surfaces: charts (`dashboard-reporting`), scrollbars, meta `color-scheme`, favicons where relevant.3839## Required Workflow40411. Confirm token readiness; list themes required.422. Choose the persistence + detection mechanism (SSR-aware if Next.js).433. Define per-theme token values; validate contrast in each.444. Plan the switch UX (toggle placement, no layout shift).455. Record the plan; hand chart/table theming notes to the dashboard skills.4647## Decision Rules4849- Components consume semantic tokens only; a theme is a token-value set, never per-component conditionals.50- Manual override beats system preference; absence of override follows the system live.51- If SSR renders themed markup, the server must know the preference (cookie) — otherwise render neutral and set it pre-paint.52- Don't add a theming abstraction for a single fixed theme; note the extension point and stop.5354## Rules5556- No hardcoded colors outside token definitions.57- Both themes ship accessible or the second theme doesn't ship.58- Theme switching must not trigger layout shift or content reflow.5960## Anti-Patterns6162- Dark mode via `filter: invert()` or ad-hoc `dark:` overrides scattered without token discipline.63- Theme state in a global store re-rendering the world on toggle instead of a root attribute + CSS variables.64- Shipping dark mode that fails contrast because only light was checked.65- SSR pages that flash light-then-dark on every load.6667## Validation Checklist6869- [ ] Themes enumerated; per-theme token values defined.70- [ ] Detection + persisted override mechanism chosen (SSR-aware if applicable).71- [ ] Flash-avoidance strategy planned.72- [ ] Contrast validated (or planned for validation) in every theme.73- [ ] No hardcoded colors bypassing tokens.7475## Definition of Done7677A recorded theming plan — themes, token values, detection/persistence, flash avoidance, and contrast validation — where switching themes changes token values only and both themes meet accessibility standards.7879## Related Skills8081`web-design-system`, `web-accessibility`, `nextjs-foundation`, `vite-react-foundation`, `dashboard-reporting`.8283## Related Knowledge8485`../../../knowledge/` (brand palette decisions).8687## Related References8889`../../../references/web/design-system/` (theme token tables — when populated).9091## Context Loading Guidance9293- **Requires:** semantic tokens, framework foundation, theme requirements.94- **Does not require:** full component inventory, data-layer detail.95- **May load:** `web-accessibility` for contrast criteria.96- **Stop when:** the theming plan is recorded.9798## Token Efficiency Guidance99100Represent themes as token-value tables. Don't enumerate component-by-component styling — the token layer makes that unnecessary.