Dark mode
Since version 5.3 Bootstrap has built-in color modes: light and dark. A mode is turned on with a single data-bs-theme attribute, and all components — cards, tables, forms, menus — recolor themselves. You do not write separate dark theme styles.
A theme for the whole page
The attribute goes on the <html> tag:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script>document.documentElement.setAttribute('data-bs-theme', 'dark');</script>
<div class="card" style="max-width: 18rem">
<div class="card-body">
<h5 class="card-title">A dark card</h5>
<input class="form-control mb-2" placeholder="Task title">
<button type="button" class="btn btn-primary">Add</button>
</div>
</div>The preview has no <html> tag of its own, so a line of JavaScript sets the attribute. In your index.html just write <html lang="en" data-bs-theme="dark">. The page background, the card and the field turned dark, the text light, and the blue button stayed blue.
A theme for one block
The attribute works on any element and applies to everything inside. This way only the header or the admin sidebar can be dark:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<div class="d-flex border">
<div class="bg-body text-body p-3" data-bs-theme="dark" style="width: 160px">
<div class="fw-bold mb-2">Tasko</div>
<div class="text-body-secondary">Overview</div>
<div class="text-body-secondary">Orders</div>
</div>
<div class="bg-body text-body p-3 flex-grow-1">Light main area</div>
</div>The left menu is dark, the right part is light. The bg-body and text-body classes take the background and text color of the current theme, so the same markup looks right in both themes.
A theme switch
The theme is just an attribute, so a switch changes it from JavaScript:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="themeSwitch">
<label class="form-check-label" for="themeSwitch">Dark theme</label>
</div>
<script>
const root = document.documentElement;
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const themeSwitch = document.querySelector('#themeSwitch');
root.setAttribute('data-bs-theme', prefersDark ? 'dark' : 'light');
themeSwitch.checked = prefersDark;
themeSwitch.addEventListener('change', () => {
root.setAttribute('data-bs-theme', themeSwitch.checked ? 'dark' : 'light');
});
</script>On load the theme matches the operating system setting: matchMedia checks the prefers-color-scheme media query. Click the switch and the preview changes theme. In a real project the user's choice is also saved to localStorage so it survives a reload.
Common mistake
Coloring blocks with bg-white, bg-light, text-dark. These are fixed colors: in dark mode such a block stays white with dark text in the middle of a dark page. For backgrounds and text that should follow the theme, use bg-body, bg-body-tertiary, text-body and text-body-secondary.