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:
darklighthigh-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
Scenario: Dark theme links are readable
- 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
lighttheme and reloads the page - THEN the
lighttheme 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:
- Stored theme in
localStorage(if available) - Stored theme in a cookie (if localStorage is unavailable)
- Default selection using environment signals
Scenario: LocalStorage persists across a later visit
- WHEN a user selects
lighttheme and later returns to the site in the same browser - THEN the site initializes in
lighttheme before first paint
Scenario: Cookie fallback is used when localStorage is unavailable
- WHEN the browser environment blocks
localStorageaccess and the user selectsdarktheme - 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
localStorageand 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:
- If forced colors / high-contrast mode is active, default to
high-contrast - Else if the system prefers light color scheme, default to
light - 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
darktolighttheme - THEN theme-affecting properties transition smoothly instead of abruptly switching
Scenario: Reduced motion disables theme animation
- WHEN
prefers-reduced-motion: reduceis set and the user switches theme - THEN the theme change occurs without noticeable animation