User Interface

Theme System Hardening Checklist

An operator-grade checklist for shipping themes without regressions in SSR, hydration, and accessibility.

Theme System Hardening Checklist

Why this exists

Theming failures are expensive because they break first impressions, accessibility, and trust. This checklist is designed for release day and post-release monitoring.

Architecture baseline

  • preference state: light, dark, system
  • system state from media query
  • resolved state used by document root
  • CSS tokens mapped through semantic variables

Pre-release checklist

SSR and first paint

  • inline bootstrap sets data-theme before app hydration
  • no first paint flash on both light and dark
  • hydration warnings remain at zero

State and persistence

  • invalid storage values are sanitized
  • cross-tab sync works via storage event
  • preference survives full restart

Accessibility and contrast

  • critical semantic pairs pass AA
  • focus ring tokens are visible in both themes
  • disabled and muted states are visually distinct

UI behavior

  • theme toggle icon communicates next action
  • aria labels match the actual action
  • transitions are smooth and non-blocking

Reference implementation

export function resolveTheme(pref: "light" | "dark" | "system", system: "light" | "dark"): "light" | "dark" {
  return pref === "system" ? system : pref;
}

export function applyTheme(theme: "light" | "dark", doc: Document = document) {
  doc.documentElement.setAttribute("data-theme", theme);
}

Release telemetry

Track event counts and rates for:

  • theme_preference_changed
  • theme_resolved
  • theme_bootstrap_fallback_used
  • theme_contrast_validation_failed

Incident response

If regressions appear:

  1. freeze theme token changes
  2. roll back last token rename
  3. run contrast validator and store tests
  4. patch bootstrap script first

Done definition

Theme work is complete only when store tests, e2e smoke, and contrast checks pass in CI and in local preflight.