Theme Management
**Referenced Files in This Document** - [main.js](file://src/assets/js/main.js) - [theme-toggling.js](file://src/assets/js/modules/theme-toggling.js) - [material-design-3-main-theme-toggle.js](file://src/assets/js/modules/material-design-3-main-theme-toggle.js) - [iaa-alliance-theme-toggle.js](file://src/assets/js/modules/iaa-alliance-theme-toggle.js) - [base.njk](file://src/_includes/layouts/base.njk) - [iaa-base.njk](file://src/_includes/layouts/iaa-base.njk) - [main.css](file://src/assets/css/main.css) - [38-material-design-3-theme-toggle.css](file://src/assets/css/modules/38-material-design-3-theme-toggle.css) - [39-material-design-3-theme-toggle-complete.css](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css) - [40-iaa-alliance-page-light-dark-mode.css](file://src/assets/css/modules/40-iaa-alliance-page-light-dark-mode.css) - [01-variables-reset.css](file://src/assets/css/modules/01-variables-reset.css)Update Summary
Changes Made
- Added comprehensive pre-paint theme bootstrap mechanism to eliminate flash-of-unstyled-content (FOUC)
- Updated theme system to default to dark mode with explicit body classes
- Enhanced dark mode CSS coverage throughout the stylesheet
- Improved theme persistence and system preference detection
Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
Introduction
This document explains the theme switching and management system used across the site. It covers:
- Pre-paint theme bootstrap mechanism to eliminate flash-of-unstyled-content (FOUC)
- IntersectionObserver-based automatic theme detection for seamless dark/light mode transitions
- Material Design 3 theming implementation with color schemes and component styling
- IAA Alliance-specific theme variations and customization options
- Theme persistence via localStorage and system preference detection
- CSS custom properties system and theme variable management
- Practical examples for customization, adding new themes, and integrating with existing styles
- Performance optimizations and guidance for extending theme functionality
Project Structure
The theme system spans front-end modules and templates:
- JavaScript modules initialize toggles and observe theme changes
- Nunjucks templates embed theme toggles and set baseline theme classes
- CSS modules define Material Design 3 color tokens, global theme states, and component-level overrides
- A consolidated stylesheet imports modular CSS files
graph TB
JS_Main["main.js"]
Mod_ThemeToggling["theme-toggling.js"]
Mod_MDToggle["material-design-3-main-theme-toggle.js"]
Mod_IAAToggle["iaa-alliance-theme-toggle.js"]
BaseTpl["base.njk"]
IAATpl["iaa-base.njk"]
CSS_Main["main.css"]
CSS_MD["38-material-design-3-theme-toggle.css"]
CSS_MD_Complete["39-material-design-3-theme-toggle-complete.css"]
CSS_IAA_Mode["40-iaa-alliance-page-light-dark-mode.css"]
CSS_Vars["01-variables-reset.css"]
JS_Main --> Mod_ThemeToggling
JS_Main --> Mod_MDToggle
JS_Main --> Mod_IAAToggle
BaseTpl --> CSS_Main
IAATpl --> CSS_Main
CSS_Main --> CSS_MD
CSS_Main --> CSS_MD_Complete
CSS_Main --> CSS_IAA_Mode
CSS_MD --> CSS_Vars
CSS_MD_Complete --> CSS_Vars
CSS_IAA_Mode --> CSS_Vars
Diagram sources
- [main.js:1-37](file://src/assets/js/main.js#L1-L37)
- [theme-toggling.js:1-24](file://src/assets/js/modules/theme-toggling.js#L1-L24)
- [material-design-3-main-theme-toggle.js:1-38](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L1-L38)
- [iaa-alliance-theme-toggle.js:1-38](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L1-L38)
- [base.njk:63](file://src/_includes/layouts/base.njk#L63)
- [iaa-base.njk:17](file://src/_includes/layouts/iaa-base.njk#L17)
- [main.css:1-47](file://src/assets/css/main.css#L1-L47)
- [38-material-design-3-theme-toggle.css:1-237](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L1-L237)
- [39-material-design-3-theme-toggle-complete.css:1-726](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L1-L726)
- [40-iaa-alliance-page-light-dark-mode.css:1-468](file://src/assets/css/modules/40-iaa-alliance-page-light-dark-mode.css#L1-L468)
- [01-variables-reset.css:30-64](file://src/assets/css/modules/01-variables-reset.css#L30-L64)
Section sources
- [main.js:1-37](file://src/assets/js/main.js#L1-L37)
- [base.njk:63](file://src/_includes/layouts/base.njk#L63)
- [iaa-base.njk:17](file://src/_includes/layouts/iaa-base.njk#L17)
- [main.css:1-47](file://src/assets/css/main.css#L1-L47)
Core Components
- Pre-paint theme bootstrap mechanism that applies saved preferences before content renders
- Theme toggle initialization for the main site and IAA Alliance page
- IntersectionObserver-based automatic theme detection for section-scoped themes
- CSS custom properties defining Material Design 3 color tokens and global theme states
- Persistent theme preferences stored in localStorage
Key responsibilities:
- Initialize toggles and bind keyboard accessibility
- Persist theme selection per domain/page
- Apply theme classes to the document body for cascading style application
- Observe sections to switch body classes for background-aware components
- Eliminate flash-of-unstyled-content through pre-paint theme application
Section sources
- [material-design-3-main-theme-toggle.js:1-38](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L1-L38)
- [iaa-alliance-theme-toggle.js:1-38](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L1-L38)
- [theme-toggling.js:1-24](file://src/assets/js/modules/theme-toggling.js#L1-L24)
- [38-material-design-3-theme-toggle.css:6-33](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L6-L33)
- [39-material-design-3-theme-toggle-complete.css:6-23](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L6-L23)
Architecture Overview
The theme system is composed of three layers:
- Initialization layer: JavaScript modules register event listeners and apply initial theme classes
- Presentation layer: CSS custom properties and theme classes drive visual styling
- Template layer: Nunjucks layouts embed toggles and set baseline theme classes
sequenceDiagram
participant DOM as "DOMContentLoaded"
participant Base as "base.njk"
participant Main as "main.js"
participant MD as "material-design-3-main-theme-toggle.js"
participant IAA as "iaa-alliance-theme-toggle.js"
participant OBS as "theme-toggling.js"
Base->>Base : "Pre-paint theme bootstrap"
Base->>DOM : "Apply data-initial-theme='dark'"
DOM->>Main : "Initialize modules"
Main->>MD : "initThemeToggle()"
MD->>MD : "Read localStorage, set body classes"
MD->>MD : "Bind click/keyboard events"
Main->>IAA : "initIAAThemeToggle()"
IAA->>IAA : "Read localStorage, set body classes"
IAA->>IAA : "Bind click/keyboard events"
Main->>OBS : "initThemeToggling()"
OBS->>OBS : "Observe [data-theme] sections"
OBS->>DOM : "Toggle on-light-bg/on-dark-bg on intersect"
Diagram sources
- [main.js:15-26](file://src/assets/js/main.js#L15-L26)
- [material-design-3-main-theme-toggle.js:3-35](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L3-L35)
- [iaa-alliance-theme-toggle.js:3-35](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L3-L35)
- [theme-toggling.js:3-21](file://src/assets/js/modules/theme-toggling.js#L3-L21)
Detailed Component Analysis
Pre-Paint Theme Bootstrap Mechanism
Updated The system now implements a pre-paint theme bootstrap mechanism to eliminate flash-of-unstyled-content (FOUC).
- Applies saved theme preference before content renders using a script in the
<head> - Sets
data-initial-themeattribute on<html>element with fallback to 'dark' - Executes immediately after CSS loads to prevent unstyled content flashes
- Ensures consistent theme application across all page loads
sequenceDiagram
participant Head as "<head> Script"
participant HTML as "<html> Element"
participant Body as "<body> Element"
participant CSS as "CSS Stylesheets"
Head->>HTML : "Set data-initial-theme='dark'"
Head->>Body : "Set class='theme-dark'"
CSS->>Body : "Apply theme-dark styles immediately"
Diagram sources
- [base.njk:29-40](file://src/_includes/layouts/base.njk#L29-L40)
- [base.njk:76](file://src/_includes/layouts/base.njk#L76)
Section sources
- [base.njk:29-40](file://src/_includes/layouts/base.njk#L29-L40)
- [base.njk:76](file://src/_includes/layouts/base.njk#L76)
Material Design 3 Theme Toggle (Main Site)
- Initializes a theme toggle element with aria attributes
- Reads a persistent preference from localStorage
- Applies theme-light/theme-dark classes to the body
- Toggles classes and persists the inverse theme on click
- Supports keyboard activation (Enter/Space)
sequenceDiagram
participant User as "User"
participant Toggle as ".theme-toggle"
participant JS as "material-design-3-main-theme-toggle.js"
participant Body as "document.body"
participant Storage as "localStorage"
User->>Toggle : "Click or press Enter/Space"
Toggle->>JS : "Event handler"
JS->>Body : "Toggle theme-light/theme-dark"
JS->>Toggle : "Set aria-checked"
JS->>Storage : "Persist 'ace-theme-preference'"
Diagram sources
- [material-design-3-main-theme-toggle.js:17-27](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L17-L27)
- [base.njk:235-252](file://src/_includes/layouts/base.njk#L235-L252)
Section sources
- [material-design-3-main-theme-toggle.js:1-38](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L1-L38)
- [base.njk:235-252](file://src/_includes/layouts/base.njk#L235-L252)
- [38-material-design-3-theme-toggle.css:52-185](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L52-L185)
- [39-material-design-3-theme-toggle-complete.css:519-724](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L519-L724)
IAA Alliance Theme Toggle (Standalone)
- Mirrors the main toggle behavior for the IAA page
- Uses a separate storage key and default theme
- Applies theme-light/theme-dark classes and updates aria state
- Persists selections independently from the main site
sequenceDiagram
participant User as "User"
participant IAA_Toggle as ".iaa-theme-toggle"
participant IAA_JS as "iaa-alliance-theme-toggle.js"
participant Body as "document.body"
participant Storage as "localStorage"
User->>IAA_Toggle : "Click or press Enter/Space"
IAA_Toggle->>IAA_JS : "Event handler"
IAA_JS->>Body : "Toggle theme-light/theme-dark"
IAA_JS->>IAA_Toggle : "Set aria-checked"
IAA_JS->>Storage : "Persist 'iaa-theme-preference'"
Diagram sources
- [iaa-alliance-theme-toggle.js:17-27](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L17-L27)
- [iaa-base.njk:74-92](file://src/_includes/layouts/iaa-base.njk#L74-L92)
Section sources
- [iaa-alliance-theme-toggle.js:1-38](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L1-L38)
- [iaa-base.njk:74-92](file://src/_includes/layouts/iaa-base.njk#L74-L92)
- [40-iaa-alliance-page-light-dark-mode.css:216-468](file://src/assets/css/modules/40-iaa-alliance-page-light-dark-mode.css#L216-L468)
IntersectionObserver-Based Automatic Theme Detection
- Observes sections marked with a data-theme attribute
- Switches body classes on-light-bg/on-dark-bg based on the intersecting section's theme
- Uses a centered viewport margin to trigger near the viewport center
flowchart TD
Start(["initThemeToggling"]) --> Query["Query [data-theme] sections"]
Query --> Exists{"Any sections found?"}
Exists --> |No| End(["Return"])
Exists --> |Yes| Observe["Create IntersectionObserver"]
Observe --> Loop["On entry: read dataset.theme"]
Loop --> Same{"Same as current?"}
Same --> |Yes| Loop
Same --> |No| SetCurrent["Set current theme"]
SetCurrent --> Toggle["Toggle 'on-light-bg'/'on-dark-bg' on body"]
Toggle --> Loop
Loop --> End
Diagram sources
- [theme-toggling.js:3-21](file://src/assets/js/modules/theme-toggling.js#L3-L21)
Section sources
- [theme-toggling.js:1-24](file://src/assets/js/modules/theme-toggling.js#L1-L24)
CSS Custom Properties and Material Design 3 Color Schemes
Updated The CSS system now includes comprehensive dark mode styling throughout the stylesheet.
- Defines Material Design system tokens at :root
- Establishes global theme states (body.theme-light/body.theme-dark)
- Provides component-level overrides for navigation, footer, cards, forms, and more
- Ensures accessibility with focus-visible outlines and semantic aria attributes
- Extensive dark mode support with comprehensive variable overrides
classDiagram
class RootCSS {
"+var(--md-sys-color-primary)"
"+var(--md-sys-color-surface)"
"+var(--md-sys-color-on-surface)"
"+var(--md-sys-color-outline)"
"+var(--md-elevation-1)"
"+var(--md-elevation-2)"
"+var(--md-elevation-3)"
}
class ThemeStates {
"body.theme-light"
"body.theme-dark"
}
class ToggleStyles {
".theme-toggle-wrapper"
".theme-toggle"
".theme-toggle__track"
".theme-toggle__handle"
".theme-toggle__icon"
}
RootCSS --> ThemeStates : "consumed by"
ThemeStates --> ToggleStyles : "drives"
Diagram sources
- [38-material-design-3-theme-toggle.css:6-33](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L6-L33)
- [39-material-design-3-theme-toggle-complete.css:6-23](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L6-L23)
- [38-material-design-3-theme-toggle.css:36-185](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L36-L185)
Section sources
- [38-material-design-3-theme-toggle.css:1-237](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L1-L237)
- [39-material-design-3-theme-toggle-complete.css:1-726](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L1-L726)
- [01-variables-reset.css:30-64](file://src/assets/css/modules/01-variables-reset.css#L30-L64)
IAA Alliance Page Theme Variations
- Provides dedicated dark and light mode variables for the IAA page
- Applies theme-specific overrides for navigation, footer, buttons, cards, and typography
- Ensures the theme toggle integrates with IAA branding and color accents
flowchart TD
IAA_Start(["IAA Page Load"]) --> SetBase["Set body class 'iaa-page theme-dark'"]
SetBase --> ApplyDark["Apply dark mode variables (--iaa-*)"]
ApplyDark --> Overrides["Apply IAA-specific component overrides"]
Overrides --> Toggle["Enable theme toggle for IAA"]
Toggle --> Persist["Persist preference in localStorage"]
Diagram sources
- [iaa-base.njk:17](file://src/_includes/layouts/iaa-base.njk#L17)
- [40-iaa-alliance-page-light-dark-mode.css:216-468](file://src/assets/css/modules/40-iaa-alliance-page-light-dark-mode.css#L216-L468)
Section sources
- [iaa-base.njk:17](file://src/_includes/layouts/iaa-base.njk#L17)
- [40-iaa-alliance-page-light-dark-mode.css:1-468](file://src/assets/css/modules/40-iaa-alliance-page-light-dark-mode.css#L1-L468)
Dependency Analysis
- main.js orchestrates initialization of theme-related modules
- Templates embed theme toggles and set baseline theme classes
- CSS modules depend on shared custom properties for consistent theming
- LocalStorage keys are scoped per toggle to avoid cross-domain conflicts
graph LR
Main["main.js"] --> MDInit["material-design-3-main-theme-toggle.js"]
Main --> IAAInit["iaa-alliance-theme-toggle.js"]
Main --> ObsInit["theme-toggling.js"]
BaseTpl["base.njk"] --> CSSMain["main.css"]
IAATpl["iaa-base.njk"] --> CSSMain
CSSMain --> MDStyles["38-material-design-3-theme-toggle.css"]
CSSMain --> MDComplete["39-material-design-3-theme-toggle-complete.css"]
CSSMain --> IAAStyles["40-iaa-alliance-page-light-dark-mode.css"]
MDStyles --> Vars["01-variables-reset.css"]
MDComplete --> Vars
IAAStyles --> Vars
Diagram sources
- [main.js:10-11](file://src/assets/js/main.js#L10-L11)
- [base.njk:235-252](file://src/_includes/layouts/base.njk#L235-L252)
- [iaa-base.njk:74-92](file://src/_includes/layouts/iaa-base.njk#L74-L92)
- [main.css:40-42](file://src/assets/css/main.css#L40-L42)
Section sources
- [main.js:1-37](file://src/assets/js/main.js#L1-L37)
- [main.css:1-47](file://src/assets/css/main.css#L1-L47)
Performance Considerations
- Pre-paint theme bootstrap: Eliminates FOUC by applying theme classes before content renders
- Efficient DOM updates: toggling two body classes per theme change minimizes repaint cost
- IntersectionObserver thresholds and margins reduce unnecessary recalculations
- CSS custom properties enable fast runtime switching without reflows
- localStorage reads/writes occur only on user interaction, avoiding frequent IO
- Consider lazy-loading theme scripts until after initial paint if needed for very large pages
[No sources needed since this section provides general guidance]
Troubleshooting Guide
Common issues and resolutions:
- Toggle not visible or interactive
- Verify the presence of the toggle element and that initialization runs after DOMContentLoaded
- Confirm the module is imported and called in main.js
- Theme does not persist
- Ensure localStorage is enabled and not blocked by browser settings
- Check that the correct storage key is used per toggle
- Flash-of-unstyled-content (FOUC) still occurs
- Verify the pre-paint bootstrap script is executing before CSS loads
- Check that
data-initial-themeattribute is being set correctly
- Background-aware components not switching
- Confirm sections have the data-theme attribute and are intersecting
- Ensure IntersectionObserver is supported or provide a polyfill fallback
- IAA toggle not affecting IAA page
- Confirm the IAA template sets the correct body classes and includes the IAA toggle markup
- Verify the IAA-specific CSS is loaded and not overridden by other styles
Section sources
- [main.js:15-26](file://src/assets/js/main.js#L15-L26)
- [theme-toggling.js:3-21](file://src/assets/js/modules/theme-toggling.js#L3-L21)
- [iaa-alliance-theme-toggle.js:3-35](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L3-L35)
- [material-design-3-main-theme-toggle.js:3-35](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L3-L35)
Conclusion
The theme management system combines JavaScript initialization, IntersectionObserver-based automatic theme detection, and a robust CSS custom properties foundation aligned with Material Design 3. The new pre-paint bootstrap mechanism eliminates flash-of-unstyled-content and ensures consistent theme application. It supports independent theme preferences for the main site and the IAA Alliance page, integrates seamlessly with existing components, and offers clear extension points for future customization.
[No sources needed since this section summarizes without analyzing specific files]
Appendices
Practical Examples
-
Customize Material Design 3 color tokens
- Modify root-level tokens in the Material Design 3 toggle stylesheet to adjust primary/surface colors and elevation shadows
- Reference: [38-material-design-3-theme-toggle.css:6-14](file://src/assets/css/modules/38-material-design-3-theme-toggle.css#L6-L14)
-
Add a new theme variant (e.g., sepia)
- Define new CSS variables for the sepia palette
- Extend global theme states to include a third body class (e.g., body.theme-sepia)
- Add component-level overrides for navigation, footer, and cards
- Reference: [39-material-design-3-theme-toggle-complete.css:20-50](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L20-L50)
-
Integrate a theme toggle into a new layout
- Add the toggle HTML structure to the layout and ensure it has the correct role, aria attributes, and tabindex
- Reference: [base.njk:235-252](file://src/_includes/layouts/base.njk#L235-L252), [iaa-base.njk:74-92](file://src/_includes/layouts/iaa-base.njk#L74-L92)
-
Enable automatic theme detection for new sections
- Add the data-theme attribute to sections requiring background-aware styling
- Reference: [theme-toggling.js:4](file://src/assets/js/modules/theme-toggling.js#L4)
-
Persist theme preferences independently
- Use a distinct localStorage key per toggle to avoid conflicts
- Reference: [material-design-3-main-theme-toggle.js:8](file://src/assets/js/modules/material-design-3-main-theme-toggle.js#L8), [iaa-alliance-theme-toggle.js:8](file://src/assets/js/modules/iaa-alliance-theme-toggle.js#L8)
-
Optimize performance for large pages
- Defer theme script initialization until after initial paint
- Use IntersectionObserver with appropriate thresholds/margins
- Minimize heavy CSS animations during theme transitions
-
Implement pre-paint theme bootstrap
- Add the theme bootstrap script to the
<head>section of your layout - Ensure the script executes before CSS loads to prevent FOUC
- Reference: [base.njk:29-40](file://src/_includes/layouts/base.njk#L29-L40)
- Add the theme bootstrap script to the
-
Enhance dark mode coverage
- Add comprehensive dark mode styles for new components
- Use theme-specific selectors (
.theme-dark .component-class) - Reference: [39-material-design-3-theme-toggle-complete.css:16-206](file://src/assets/css/modules/39-material-design-3-theme-toggle-complete.css#L16-L206)