Files
2026-02-10 22:37:29 -05:00

4.4 KiB

Purpose

Define site-wide theme support (dark, light, high-contrast) using CSS tokens and an application mechanism that can switch across the entire UI.

Requirements

Requirement: Site themes

The site MUST support three themes:

  • dark
  • light
  • high-contrast

Themes MUST be applied by setting a data-theme attribute on the root document element (<html>).

Scenario: Dark theme active

  • WHEN data-theme="dark" is set on <html>
  • THEN the site's background, text, and component styling reflect the dark palette

Scenario: Light theme active

  • WHEN data-theme="light" is set on <html>
  • THEN the site's background, text, and component styling reflect the light palette

Scenario: High contrast theme active

  • WHEN data-theme="high-contrast" is set on <html>
  • THEN the site uses a high-contrast palette with a clearly visible focus ring and high-contrast borders

Requirement: Theme tokens meet contrast intent

For each supported theme (dark, light, high-contrast), the theme token pairs used for primary text and primary surfaces MUST meet WCAG 2.2 AA contrast intent.

At minimum:

  • primary body text on the primary background MUST be high-contrast
  • link text on the primary background MUST be distinguishable and meet contrast intent
  • secondary labels on the primary background MUST remain readable

Scenario: Dark theme text is readable

  • WHEN data-theme="dark" is active
  • THEN primary text remains readable against primary surfaces without low-contrast combinations
  • WHEN data-theme="dark" is active
  • THEN links in common surfaces are readable against their background

Requirement: Theme persistence

The site MUST persist the user's theme selection so it is retained across page loads and navigations.

Persistence MUST be stored locally in the browser (e.g., localStorage).

Scenario: Theme persists across reload

  • WHEN the user selects light theme and reloads the page
  • THEN the light theme remains active

Requirement: Theme persistence works across visits with fallback

The site MUST persist the user's theme selection across visits so returning users see the last-selected theme.

The site MUST use client-side persistence and MUST support a fallback mechanism:

  • Primary: localStorage
  • Fallback: a client-side cookie

The effective theme selection order MUST be:

  1. Stored theme in localStorage (if available)
  2. Stored theme in a cookie (if localStorage is unavailable)
  3. Default selection using environment signals

Scenario: LocalStorage persists across a later visit

  • WHEN a user selects light theme and later returns to the site in the same browser
  • THEN the site initializes in light theme before first paint
  • WHEN the browser environment blocks localStorage access and the user selects dark theme
  • THEN the theme is persisted using a client-side cookie and is restored on the next visit

Scenario: No persistence available falls back to defaults

  • WHEN both localStorage and cookie persistence are unavailable
  • THEN the site falls back to default theme selection using environment signals

Requirement: Default theme selection

If the user has not explicitly selected a theme, the site MUST choose a default theme using environment signals.

Default selection order:

  1. If forced colors / high-contrast mode is active, default to high-contrast
  2. Else if the system prefers light color scheme, default to light
  3. Else default to dark

Scenario: No stored preference uses system settings

  • WHEN the user has no stored theme preference
  • THEN the site selects a default theme based on forced-colors and prefers-color-scheme

Requirement: Theme switching transition

Theme changes initiated by the user MUST transition smoothly.

The transition MUST be disabled or substantially reduced when prefers-reduced-motion: reduce is set.

Scenario: Smooth transition on switch

  • WHEN the user switches from dark to light theme
  • THEN theme-affecting properties transition smoothly instead of abruptly switching

Scenario: Reduced motion disables theme animation

  • WHEN prefers-reduced-motion: reduce is set and the user switches theme
  • THEN the theme change occurs without noticeable animation