Managing Dynamic Themes in Carbon with CSS Custom Properties
Learn how to implement dynamic dark and light modes using Carbon Design System's CSS custom properties and design tokens for seamless UI transitions.
11 Sept 2025, 22:49 UTC

Implementing a dark mode often results in a maintenance burden of nested CSS overrides or complex JavaScript logic that manually updates classes on every single UI component. When a design system grows, managing these state changes across hundreds of elements becomes unsustainable.
The Carbon Design System solves this by leveraging CSS custom properties (CSS variables). Instead of hard-coding hex values into components, Carbon uses design tokens. By updating the value of these tokens at the root level, the entire application updates instantly without requiring a page reload or heavy DOM manipulation.
The Mechanism: Design Tokens
Carbon's theming relies on design tokens—abstract names that represent visual attributes like color, spacing, or typography. For example, a token such as --cds-layer-01 does not represent a specific color, but rather a functional role (a background layer).
In a light theme, --cds-layer-01 might resolve to a light grey. In a dark theme, the same token resolves to a deep charcoal. Because the components reference the variable name rather than a static value, they react automatically when the variable's definition changes in the CSS cascade.
Practical Implementation: The Theme Toggle
To implement dynamic switching, you need to define your theme maps and a mechanism to toggle the attribute on the root element. This approach ensures that all components referencing Carbon tokens update simultaneously.
Run the following CSS in your global stylesheet to define the theme relationship:
/* Default Light Theme */
:root {
--cds-layer-01: #f4f4f4;
--cds-text-01: #161616;
--cds-primary: #0f62fe;
}
/* Dark Theme Overrides */
[data-theme='dark'] {
--cds-layer-01: #161616;
--cds-text-01: #f4f4f4;
--cds-primary: #3b82ff;
}
/* Component using tokens */
.carbon-card {
background-color: var(--cds-layer-01);
color: var(--cds-text-01);
border: 1px solid var(--cds-primary);
padding: 1rem;
}
Use the following JavaScript to handle the state transition. This should be executed in the browser context, typically within a main application script:
const toggleBtn = document.getElementById('theme-toggle');
const rootElement = document.documentElement;
toggleBtn.addEventListener('click', () => {
const currentTheme = rootElement.getAttribute('data-theme');
const targetTheme = currentTheme === 'dark' ? 'light' : 'dark';
rootElement.setAttribute('data-theme', targetTheme);
});
Verification and Diagnostics
To confirm the theme is applying correctly, use the browser's Developer Tools (F12):
- Inspect the
<html>element to ensure thedata-themeattribute toggles between 'light' and 'dark' upon clicking the button. - Select a themed component (e.g.,
.carbon-card) and open the Computed styles tab. - Search for the specific variable (e.g.,
--cds-layer-01) and verify that the resolved color value changes in real-time.
Trade-offs and Limitations
While this method is performant, there are specific engineering constraints:
- Hard-coded Values: Any component using a static hex code instead of a
var()reference will not respond to theme changes, creating visual inconsistencies. - Browser Support: This relies on CSS custom properties. While supported in all modern browsers, legacy browsers (like IE11) will ignore these variables and fall back to default styles.
- Flash of Unstyled Content (FOUC): If the theme state is stored in localStorage, applying the attribute via JavaScript after the DOM loads can cause a visible "flicker" from light to dark. This is typically mitigated by placing a small blocking script in the
<head>to set the attribute before the body renders.
Rollback Procedure
If the dynamic theming causes rendering regressions, remove the data-theme attribute from the <html> tag and delete the [data-theme='dark'] block from your CSS. The application will revert to the default :root definitions.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.