The Quantum Design System provides a semantic token system for light and dark mode. Components should read from those shared variables first, then expose a small number of component-level aliases only where customization is genuinely needed.
The theming system uses CSS variables (custom properties) in two layers: paired light/dark source tokens, and the unsuffixed semantic tokens that components should actually consume.
/* Brand colors stay stable */
:root {
--brand-dark-blue: #3E495B;
--brand-middle-blue: #445E89;
--brand-green: #00BE34;
}
/* Theme source tokens */
:root {
--theme-background-primary-light: #FFFFFF;
--theme-background-primary-dark: #222B45;
--theme-text-primary-light: #333333;
--theme-text-primary-dark: #FFFFFF;
--theme-accent-primary-light: var(--brand-middle-blue);
--theme-accent-primary-dark: #709AE0;
/* Active semantic tokens (light by default) */
--theme-background-primary: var(--theme-background-primary-light);
--theme-text-primary: var(--theme-text-primary-light);
--theme-accent-primary: var(--theme-accent-primary-light);
}
Dark mode only remaps the active semantic tokens to the dark source set:
[data-theme="dark"] {
--theme-background-primary: var(--theme-background-primary-dark);
--theme-text-primary: var(--theme-text-primary-dark);
--theme-accent-primary: var(--theme-accent-primary-dark);
}
Use the unsuffixed semantic tokens in components. Reserve the explicit *-light and *-dark tokens for fixed-theme surfaces, documentation, or controlled overrides.
The theming system provides a set of semantic color variables that adapt to the current theme:
Background Primary
var(--theme-background-primary)
Main background color
Background Secondary
var(--theme-background-secondary)
Secondary background color
Background Tertiary
var(--theme-background-tertiary)
Tertiary background color
Text Primary
var(--theme-text-primary)
Main text color
Text Secondary
var(--theme-text-secondary)
Secondary text color
Text Tertiary
var(--theme-text-tertiary)
Tertiary text color
Accent Primary
var(--theme-accent-primary)
Main accent color
Accent Secondary
var(--theme-accent-secondary)
Secondary accent color
Success
var(--theme-success)
Success state color
Warning
var(--theme-warning)
Warning state color
Error
var(--theme-error)
Error state color
Info
var(--theme-info)
Info state color
To make your components theme-aware, simply use the theme variables in your CSS:
/* Example component CSS */
.my-component {
background-color: var(--theme-background-primary);
color: var(--theme-text-primary);
border: 1px solid var(--theme-border-primary);
}
.my-component button {
background-color: var(--theme-accent-primary);
color: var(--theme-text-on-accent-primary);
}
.my-component button:hover {
background-color: var(--theme-accent-secondary);
}
Components will automatically adapt to theme changes without any additional JavaScript logic.
In web components with Shadow DOM, import the base CSS and use the variables in your shadow root:
// Make sure the base CSS is loaded
loadBaseCSS();
// In your render method
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
background-color: var(--theme-background-primary);
color: var(--theme-text-primary);
}
button {
background-color: var(--theme-accent-primary);
color: var(--theme-text-on-accent-primary);
}
</style>
<div>
<button>Click me</button>
</div>
`;
}
The theme system includes a JavaScript API for programmatic control:
import themeManager from '/assets/components/shared/theme-manager.js';
// Get current theme
const isDark = themeManager.isDarkTheme();
const currentTheme = themeManager.getTheme(); // 'light' or 'dark'
// Check if auto theme is enabled
const isAutoTheme = themeManager.isAutoTheme();
// Set theme explicitly
themeManager.setTheme('dark'); // or 'light'
// Toggle between light and dark
const newTheme = themeManager.toggleTheme();
// Enable automatic theme based on system preference
themeManager.enableAutoTheme();
You can listen for theme change events:
// Listen for theme changes
document.addEventListener('qds-theme-change', (event) => {
const { theme, dark } = event.detail;
console.log(`Theme changed to: ${theme}`);
console.log(`Dark mode: ${dark}`);
});
The <qds-theme-switch> component provides a user interface for changing themes:
Include the component in your HTML:
<script type="module" src="/assets/components/theme-switch/qds-theme-switch.js"></script>
<qds-theme-switch></qds-theme-switch>
| Attribute | Type | Description |
|---|---|---|
dark |
Boolean | Whether the current theme is dark |
auto |
Boolean | Whether to use system preferences |
| Event | Detail | Description |
|---|---|---|
theme-change |
{ dark: boolean, theme: string } |
Fired when the theme is changed |
Prefer component-local aliases that still resolve to shared theme tokens. That keeps components consistent across light and dark mode while allowing targeted adjustments.
qds-powerbi-embed {
--powerbi-embed-background: var(--theme-background-elevated);
--powerbi-embed-border-color: var(--theme-border-primary);
}
qds-color-helper {
--color-helper-background: var(--theme-background-primary);
--color-helper-muted-background: var(--theme-background-secondary);
}
When a component needs its own styling hooks, alias those hooks back to the semantic tokens instead of duplicating light and dark values in page code.
:root {
--docs-card-surface: var(--theme-background-primary);
--docs-card-border: var(--theme-border-primary);
--docs-card-text: var(--theme-text-primary);
}
Quantum Design System Theming v1.0.0