Implementing Custom Themes
Relevant source files
The following files were used as context for generating this wiki page:
The theme implementation in the Calculator project provides a robust system for switching between light and dark visual modes. This system leverages CSS custom properties (design tokens) and a JavaScript-driven toggle mechanism to ensure a consistent user experience that can also respect system-level preferences.
The primary goal of this architecture is to decouple the visual styling from the functional logic of the calculator, allowing for easy updates to the color palette, shadows, and spacing without altering the underlying HTML structure or calculation algorithms.
Design Token Architecture
The project utilizes CSS custom properties (variables) defined within the :root pseudo-class to establish a centralized design system. These tokens cover colors, spacing, shadows, and typography.
Color Tokens and Theming
The system defines two primary states: a default "light" theme and an explicit "dark" theme. The light theme properties are applied to :root or elements with the [data-theme="light"] attribute, while the dark theme overrides these values when the [data-theme="dark"] attribute is present on the <html> element.
| Token Category | Variables | Description |
|---|---|---|
| Backgrounds | --color-bg, --color-surface, --color-surface-2 | Defines the main page background and card surface colors. |
| Typography | --color-text, --color-text-muted, --color-text-faint | Manages text hierarchy through varying levels of contrast. |
| Accents | --color-primary, --color-primary-hover | Used for primary actions like the equals button and logo icon. |
| Interactive | --color-btn-num, --color-btn-op, --color-btn-fn | Specific background colors for different calculator button types. |
Sources: calculator.html:15-54, calculator.html:56-78
Adaptive System Preference
In addition to explicit attributes, the system uses a media query to automatically apply dark theme variables if the user's operating system is set to dark mode and no explicit theme has been chosen.
Sources: calculator.html:79-92
Theme Switching Logic
The theme toggle functionality is encapsulated within an Immediately Invoked Function Expression (IIFE) in the script section of the application. This ensures the theme is initialized correctly upon page load.
Initialization and Interaction Flow
- Detection: The script first checks the user's system preference using
matchMedia('(prefers-color-scheme: dark)'). - Application: It sets the
data-themeattribute on thedocument.documentElementbased on the detection. - UI Update: The toggle button's internal SVG icon and
aria-labelare updated to reflect the current state. - Toggle: Upon clicking the theme toggle button, the state is flipped, and the
data-themeattribute is updated, triggering CSS transitions.
The following diagram illustrates the theme initialization and toggle sequence:
Implementation Details
CSS Transition Effects
To ensure a smooth visual experience, the body and various UI components like buttons and the calculator card include transition properties tied to the --transition token (140ms cubic-bezier).
body {
transition: background var(--transition), color var(--transition);
}
.calc {
transition: background var(--transition), box-shadow var(--transition);
}
Sources: calculator.html:105-106, calculator.html:138-139
Component-Specific Styling
Buttons use the oklch color function to derive border and shadow colors dynamically from the text color variables, ensuring that borders remain subtle and proportional regardless of the active theme.
.btn {
border: 1px solid oklch(from var(--color-text) l c h / 0.06);
}
Sources: calculator.html:187, calculator.html:131
Conclusion
The custom theme implementation in this project is a modern, CSS-first approach that prioritizes performance and accessibility. By using data-theme attributes and CSS variables, the application achieves a seamless transition between light and dark modes while maintaining a single source of truth for the design system.