Theming System

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.

Key Features

CSS Variables

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.

Theme Colors

The theming system provides a set of semantic color variables that adapt to the current theme:

Background Colors

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 Colors

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 Colors

Accent Primary

var(--theme-accent-primary)

Main accent color

Accent Secondary

var(--theme-accent-secondary)

Secondary accent color

State Colors

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

Using Themes in Components

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.

For Web Components

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>
  `;
}

JavaScript API

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();

Event Listening

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}`);
});

Theme Switch Component

The <qds-theme-switch> component provides a user interface for changing themes:

Installation

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>

Attributes

Attribute Type Description
dark Boolean Whether the current theme is dark
auto Boolean Whether to use system preferences

Events

Event Detail Description
theme-change { dark: boolean, theme: string } Fired when the theme is changed

Component Overrides

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);
}

Theme-Aware Aliases

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