Bootstrap Themes
Bootstrap 5.3 introduced a native color mode system for light and dark themes. This lesson covers how to enable, customize, and extend Bootstrap's theming support.
Bootstrap Themes Overview
Setting data-bs-theme="dark" on the <html> element (or any container) switches a set of CSS custom properties to their dark-mode values, automatically adjusting background colors, text colors, borders, and component styling across the whole page or just that scoped section.
Beyond the built-in light and dark modes, you can define your own custom theme by combining Sass variable overrides for the base palette with additional CSS variable overrides scoped to a custom data-bs-theme value, letting users switch between more than just two themes.
| Concept | Description | Common Usage |
| data-bs-theme="light"/"dark" | Built-in color mode switch | Toggling the whole page or a section's theme |
| Color mode CSS variables | Root variables that change per theme | Backgrounds, text, and border colors adapting automatically |
| Scoped theming | data-bs-theme on a nested container | Mixing themes within one page, like a dark sidebar |
| JavaScript theme persistence | Storing preference in localStorage | Remembering a user's chosen theme across visits |
| Custom named themes | Extending beyond light/dark with your own values | Multi-brand or multi-tenant theming |
Bootstrap Themes Example
<html lang="en" data-bs-theme="light">
...
<div class="card" data-bs-theme="dark">
<div class="card-body">This card renders in dark mode even though the page is light.</div>
</div>
</html>
<script>
const stored = localStorage.getItem("theme") || "light";
document.documentElement.setAttribute("data-bs-theme", stored);
function setTheme(theme) {
document.documentElement.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
}
</script>
The outer html element sets the page-wide theme to light, while the nested card explicitly overrides it to dark, showing that data-bs-theme can be scoped to any container, not just the root. The script demonstrates a common persistence pattern: reading a saved preference from localStorage on load and providing a setTheme function to update and remember the user's choice.
Top 10 Bootstrap Themes Examples
These are the theming patterns you'll use to support light, dark, and custom color modes.
| # | Example | Syntax |
| 1 | Enable light theme | <html data-bs-theme="light"> |
| 2 | Enable dark theme | <html data-bs-theme="dark"> |
| 3 | Scoped dark section | <div data-bs-theme="dark" class="p-4">...</div> |
| 4 | Read current theme in JS | document.documentElement.getAttribute('data-bs-theme') |
| 5 | Set theme in JS | document.documentElement.setAttribute('data-bs-theme', 'dark'); |
| 6 | Persist theme in localStorage | localStorage.setItem('theme', 'dark'); |
| 7 | Theme toggle button | <button onclick="toggleTheme()">Toggle Theme</button> |
| 8 | Respect OS preference | window.matchMedia('(prefers-color-scheme: dark)').matches |
| 9 | Override a variable per theme | [data-bs-theme="dark"] { --bs-body-bg: #0f172a; } |
| 10 | Custom named theme attribute | <html data-bs-theme="brand-dark"> |
Popular Real-World Bootstrap Themes Examples
These theming patterns are common for dashboards, SaaS products, and content sites offering dark mode.
| Scenario | Pattern |
| App-wide dark mode toggle in settings | <button class="btn btn-outline-secondary" onclick="toggleTheme()">Toggle Dark Mode</button> |
| Respecting system dark mode on first visit | const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
| Persisting theme choice across sessions | localStorage.setItem('theme', theme); |
| Dark code editor panel inside a light dashboard | <div class="card" data-bs-theme="dark"><pre>code</pre></div> |
| Marketing site permanently in dark mode | <html data-bs-theme="dark"> |
| Multi-brand theme switching for a SaaS platform | <html data-bs-theme="brand-acme"> |
| Theme-aware chart or illustration colors | const isDark = document.documentElement.getAttribute('data-bs-theme') === 'dark'; |
| Accessible high-contrast theme option | <html data-bs-theme="high-contrast"> |
Best Practices
- Read the user's saved theme preference before first paint to avoid a flash of the wrong theme.
- Respect prefers-color-scheme as a sensible default when no explicit preference is stored yet.
- Scope data-bs-theme to specific containers when only part of the page needs a different mode.
- Test every custom component and color override in both light and dark modes.
- Provide a visible, easy-to-find control for switching themes rather than hiding it deep in settings.
- Keep custom theme names descriptive if you go beyond simple light/dark, like brand-dark or high-contrast.
- Verify color contrast ratios independently for each theme you support.
Common Mistakes
- Setting the theme only after the page renders, causing a visible flash of the default theme.
- Forgetting to test custom components and colors specifically in dark mode.
- Not persisting the user's theme choice, forcing them to reselect it on every visit.
- Assuming data-bs-theme only works on the html element, when it can be scoped anywhere.
- Overriding colors with hardcoded hex values instead of theme-aware CSS variables, breaking dark mode.
- Ignoring prefers-color-scheme entirely and forcing a single default theme on all new visitors.
Key Takeaways
- data-bs-theme enables Bootstrap's built-in light and dark color modes.
- The attribute can be scoped to the whole page or to individual containers.
- JavaScript and localStorage together provide persistent, user-controlled theme switching.
- Custom themes can extend beyond light/dark by defining your own data-bs-theme values.
- Testing color contrast and component appearance across every supported theme is essential.
Pro Tip
Set the initial data-bs-theme attribute in an inline script placed in the document head, before any CSS loads, so returning visitors see their chosen theme immediately instead of a brief flash of the default.