Color Modes (Dark Mode)

Before Bootstrap 5.3, adding a dark mode to a site like TrailMap meant writing a whole parallel set of overrides — a dark background here, a lighter text color there, checking every component by hand. Bootstrap 5.3 added a built-in color mode system instead: set one attribute, and every component's colors — buttons, cards, forms, navbars, borders — switch to a matching dark palette automatically, because they were never hardcoded colors to begin with. They're CSS custom properties that Bootstrap redefines per mode.

The data-bs-theme Attribute

Add data-bs-theme="dark" to the <html> element and the entire TrailMap page re-themes instantly — no JavaScript required for the theming itself, no duplicate stylesheet, no page reload:

<html lang="en" data-bs-theme="dark">
  ...
</html>

Remove the attribute, or set it to "light", and TrailMap goes back to its normal palette. Every component already ships CSS rules scoped to [data-bs-theme="dark"], so this single attribute is the entire mechanism.

What Bootstrap Redefines Under the Hood

Bootstrap's components don't reference literal colors like #fff in their CSS — they reference CSS variables such as --bs-body-bg and --bs-body-color. Switching data-bs-theme just points those variables at different values:

[data-bs-theme="dark"] {
  --bs-body-color: #dee2e6;
  --bs-body-bg: #212529;
  --bs-border-color: #495057;
  /* ...and dozens more, per component */
}

Because a card's border, a button's text, and a navbar's background all read from these same shared variables rather than fixed values, one attribute change cascades correctly through every component TrailMap uses, including ones added later in the project without any extra dark-mode work.

Worked Example: A TrailMap Dark Mode Toggle

A real toggle needs a small bit of plain JavaScript to flip the attribute and remember the choice — Bootstrap doesn't ship a toggle button itself, only the CSS mechanism it flips:

<button id="themeToggle" class="btn btn-outline-secondary" type="button">
  <i class="bi bi-moon-stars"></i> Toggle Dark Mode
</button>
const toggle = document.getElementById('themeToggle');
const html = document.documentElement;

// restore a saved preference on page load
const saved = localStorage.getItem('trailmap-theme');
if (saved) html.setAttribute('data-bs-theme', saved);

toggle.addEventListener('click', function() {
  const current = html.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
  html.setAttribute('data-bs-theme', current);
  localStorage.setItem('trailmap-theme', current);
});
Note: Bootstrap's JavaScript is only needed for interactive components like dropdowns and modals — the color mode switch itself is plain CSS plus this one small script, so it works even on pages that load none of Bootstrap's JS bundle.

Scoping a Color Mode to One Section

data-bs-theme isn't limited to <html>. Setting it on any container re-themes just that container, which is handy for a permanently-dark TrailMap sidebar sitting inside an otherwise light page:

<div class="p-3" data-bs-theme="dark">
  <div class="card">
    <div class="card-body">Saved Trails</div>
  </div>
</div>
Next: With dark mode wired up, Bootstrap Icons adds the icon library TrailMap's moon toggle button and trail cards use.