How to Add Dark Mode to a Bootstrap 5 Theme
Dark mode is built into Bootstrap 5.3, not an add-on. To turn it on you add data-bs-theme="dark" to the <html> element; from there you can add a toggle, sync it to the operating system, customize the dark palette, and even define your own color modes. This guide covers all of that, including the one detail most tutorials miss: how to stop the page from flashing the wrong theme on load. It builds on the color system and the complete customization guide.
Turn dark mode on
Add the data-bs-theme attribute to the <html> element (or any element you want themed):
<html lang="en" data-bs-theme="dark">
Every component inside that scope (backgrounds, text, borders, cards, dropdowns, form controls) switches to its dark variant automatically. You can also scope it to a single section, which is handy for a dark hero or footer on an otherwise light page:
<div data-bs-theme="dark">
<div class="card">This card is dark even on a light page</div>
</div>
How color modes actually work
Under the hood, [data-bs-theme="dark"] simply redefines Bootstrap’s CSS custom properties (--bs-body-bg, --bs-body-color, --bs-border-color, the -subtle and -emphasis color families, and so on) with their dark values. Because every Bootstrap component reads those variables rather than hardcoded colors, flipping the attribute re-themes everything instantly, with no recompile and no extra stylesheet. That mechanism is the key to the rest of this guide.
Add a light / dark toggle
Because the mode is just an attribute, a toggle is a few lines of JavaScript. Store the choice so it survives reloads:
const setTheme = (theme) => {
document.documentElement.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
};
document.querySelector("#theme-toggle").addEventListener("click", () => {
const current = document.documentElement.getAttribute("data-bs-theme");
setTheme(current === "dark" ? "light" : "dark");
});
Avoid the flash of the wrong theme
If you set the theme with a normal script at the bottom of the page, the browser paints the default (light) theme first and then snaps to dark, a jarring flash on every load. The fix is to set the attribute before first paint, with a tiny inline script in the <head>, before any content:
<head>
<script>
(function () {
var saved = localStorage.getItem("theme");
var os = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
document.documentElement.setAttribute("data-bs-theme", saved || os);
})();
</script>
<!-- stylesheets, etc. -->
</head>
This runs synchronously before the body renders, so the correct theme is applied from the very first frame. It is the single most important detail for a polished dark mode.
Sync with the operating system
The snippet above already falls back to the OS preference. To make an “auto” mode that follows the OS live (only when the user has not made an explicit choice), listen for changes:
matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
if (!localStorage.getItem("theme")) {
document.documentElement.setAttribute("data-bs-theme", e.matches ? "dark" : "light");
}
});
Customize the dark palette
Bootstrap keeps dark-mode values in variables ending in -dark, defined in _variables-dark.scss. Override them alongside your normal variables to brand the dark theme:
@import "bootstrap/scss/functions";
// Shared (both modes)
$primary: #2f55ff;
// Dark-mode specific
$body-bg-dark: #0b1020;
$body-color-dark: #c9d1e3;
$border-color-dark: #1f2740;
@import "bootstrap";
In 5.3 the -subtle and -emphasis color families also have dark variants, so alerts, list groups, and tinted backgrounds stay legible in dark mode without manual work. The colors a theme exposes are exactly the ones the builder lets you edit, so you can tune both palettes visually and export them together.
Make your own components respect the mode
Custom components only flip automatically if they read Bootstrap’s CSS variables instead of hardcoded colors. Build them on the tokens and they get dark mode for free:
/* Flips with the mode, no extra rules needed */
.promo-banner {
background: var(--bs-body-bg);
color: var(--bs-body-color);
border: 1px solid var(--bs-border-color);
}
If you hardcode background: #fff, that component will stay white in dark mode, the most common dark-mode bug.
Create your own color mode
Color modes are not limited to light and dark. Define your own value and set its CSS variables:
[data-bs-theme="midnight"] {
--bs-body-bg: #05060f;
--bs-body-color: #aab4d4;
--bs-primary: #7b5cff;
}
<html data-bs-theme="midnight">
This is ideal for a high-contrast mode, a brand-specific dark variant, or a seasonal theme.
Use your exported file
Drop the exported _variables.scss into the override slot (after functions, before the rest of Bootstrap) and recompile, then add the data-bs-theme attribute and your toggle. If you exported the compiled CSS, link bootstrap.min.css and set the attribute, no build step required. See how to export a Bootstrap theme for the full workflow.
Next steps
Dark mode pairs best with a considered color system, and both run on the same Sass variable foundation. The visual builder previews light and dark side by side and exports real Bootstrap Sass and CSS in one go.
FAQ
How do I enable dark mode in Bootstrap 5?
Add data-bs-theme="dark" to the <html> element (or any container you want themed). Bootstrap 5.3 has dark mode built in, so every component inside that scope switches to its dark variant automatically.
How do I add a dark mode toggle?
Toggle the data-bs-theme attribute on <html> with a button and save the choice in localStorage. To avoid a flash of the wrong theme on load, set the attribute from a small inline script in the <head> before the page renders.
How do I stop the page flashing light before dark mode loads?
Set data-bs-theme synchronously in an inline <head> script that runs before the body, reading the saved choice or the OS preference. Setting it later (for example in a script at the end of the page) causes the light theme to paint first.
How do I customize the dark mode colors?
Override the -dark Sass variables such as $body-bg-dark, $body-color-dark, and $border-color-dark before importing Bootstrap, or set them visually in the builder and export. Custom components should use the --bs-* CSS variables so they follow the mode automatically.
Try it in the builder
Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.
Open the Builder