Bootstrap 5 Runtime Theming with CSS Variables
Bootstrap 5 lets you change themes on the fly by overriding CSS custom properties. Learn how to use the --bs-* variables and data-bs-theme to switch colors without recompiling Sass.
01 Sept 2025, 14:29 UTC

Problem
Modern web apps often need to switch themes—light, dark, brand colors—without rebuilding the entire CSS bundle. Traditional Bootstrap 4 relied on Sass variables that required recompilation for every change. This makes runtime theming cumbersome and slows development cycles.
Thesis
Bootstrap 5’s CSS‑custom‑property layer gives you a single source of truth for design tokens. By overriding the --bs-* variables on any element, you can change the look of buttons, alerts, links, and form controls instantly. Coupled with the data-bs-theme attribute, you can implement dark mode with just a class toggle.
Core Design Tokens in Bootstrap 5
Bootstrap exposes its Sass variables as CSS custom properties prefixed with --bs-. They are defined on :root and cascade normally. Example tokens include:
| Token | Purpose |
|---|---|
--bs-primary | Primary button and link color |
--bs-secondary | Secondary button color |
--bs-success | Success alert background |
--bs-danger | Danger alert background |
All component styles reference these variables, so changing a single token updates every element that uses it.
Scoped Overrides
You can override the variables on any container element to create isolated themes. The overrides cascade only inside that scope, keeping the rest of the page unaffected.
/* theme.css */
:root {
--bs-primary: #0d6efd; /* default blue */
}
/* dark-theme.css */
[data-bs-theme="dark"] {
--bs-primary: #0d6efd;
--bs-body-bg: #212529;
--bs-body-color: #f8f9fa;
}
Apply the attribute on <html> or any container:
<html data-bs-theme="dark">
<body>…</body>
</html>
Bootstrap’s component CSS automatically picks up the new values because it reads the variables at render time.
Dark Mode via data-bs-theme
Bootstrap ships with predefined variable sets for light and dark. Toggling the attribute triggers a cascade of new values without any extra CSS files.
// toggle-theme.js
const toggle = () => {
const html = document.documentElement;
const current = html.getAttribute('data-bs-theme');
html.setAttribute('data-bs-theme', current === 'dark' ? 'light' : 'dark');
};
document.getElementById('themeBtn').addEventListener('click', toggle);
Attach id="themeBtn" to a button to test the switch. Open devtools and inspect --bs-primary under :root to confirm the value changes.
Example: Runtime Primary Color Switch
Below is a minimal page that lets you change the primary color on the fly by editing a CSS rule. No Sass recompilation is needed.
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
/* Override primary color in this scope */
.theme-override {
--bs-primary: #d63384; /* pink */
}
</style>
</head>
<body>
<div class="container py-4 theme-override">
<button class="btn btn-primary me-2">Primary Button</button>
<a href="#" class="link-primary me-2">Primary Link</a>
<div class="alert alert-primary" role="alert">Primary Alert</div>
</div>
</body>
</html>
Reload the page and inspect the computed color of the button. It will match the pink value defined in .theme-override. Adding more elements inside the container will automatically adopt the new primary color.
Trade‑offs and Limitations
- Performance: Deeply nested overrides can trigger extra style recalculations. Keep theme scopes shallow when possible.
- Debugging: Determining which variable source is applied becomes harder when many scopes overlap. Use devtools’ "Computed" tab to trace the origin.
- JavaScript Components: Some components (e.g.,
Modal) compute inline styles on initialization. Changing variables after initialization may not update their appearance until the component is re‑rendered or re‑initialized. - Bootstrap 4 Compatibility: This approach only works with Bootstrap 5.x. Bootstrap 4 does not expose variables as CSS custom properties.
Actionable Closing
To adopt runtime theming in your project:
- Include Bootstrap 5 CSS (no Sass needed).
- Define overrides in a dedicated stylesheet using the
--bs-*variables. - Use
data-bs-themeon<html>or a container to switch between light and dark. - For dynamic changes, update the variables via JavaScript or CSS classes and re‑initialize any components that rely on inline styles.
- Verify by inspecting computed styles in devtools and ensuring all UI elements reflect the new theme.
By treating design tokens as runtime variables, you gain flexibility without sacrificing the consistency that Bootstrap’s component library provides.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.