Skip to content
Bootstrap Advanced — Dark Mode, Customization & JavaScript API Explained

Bootstrap Advanced — Dark Mode, Customization & JavaScript API Explained

DodaTech Updated Jun 6, 2026 9 min read

Bootstrap advanced techniques let you customize the framework to match your brand, enable dark mode, build from Sass source, and control interactive components via JavaScript.

What You’ll Learn

  • Enable dark mode globally or on specific components
  • Override Bootstrap’s CSS variables for runtime theming
  • Customize Bootstrap with Sass variable overrides
  • Build Bootstrap from source with npm and sass
  • Control interactive components with the JavaScript plugin API
  • Implement RTL support for right-to-left languages

Why Advanced Customization Matters

Out-of-the-box Bootstrap works, but every brand has its own colors, spacing, and visual identity. Hardcoding overrides on top of Bootstrap creates maintenance headaches. Using Bootstrap’s customization system keeps your theme clean and upgrade-safe.

At DodaTech, Durga Antivirus Pro uses a custom Bootstrap build with brand colors and dark mode for its security dashboard. Doda Browser implements system-preference-based theme switching using Bootstrap 5.3+’s CSS variables. Both benefit from the same framework with different themes.

Your Learning Path

    flowchart LR
  A[Bootstrap Utilities] --> B[Bootstrap Advanced]
  B --> C[Bootstrap Reference]
  B:::current

  classDef current fill:#0d6efd,color:#fff,stroke:#0a58ca,stroke-width:2px
  
Prerequisites: You need all prior Bootstrap tutorials (especially Bootstrap Utilities), JavaScript basics, and familiarity with the command line. The Sass section requires Node.js and npm installed.

Dark Mode (Bootstrap 5.3+)

Bootstrap 5.3 introduced built-in dark mode using CSS custom properties and the data-bs-theme attribute. You don’t need a separate dark CSS file.

Global Dark Mode

<!-- Add data-bs-theme="dark" to the <html> element.
     Every component on the page automatically uses dark colors. -->
<html lang="en" data-bs-theme="dark">

Per-Component Dark Mode

<!-- You can mix themes on the same page.
     This card uses dark mode while the rest of the page uses light. -->
<div class="card" data-bs-theme="dark">
    <div class="card-body">
        <h5 class="card-title">Dark Card</h5>
        <p class="card-text">This card is always in dark mode.</p>
    </div>
</div>

JavaScript Theme Toggle

<button id="themeToggle" class="btn btn-outline-primary">Toggle Dark Mode</button>

<script>
    function toggleTheme() {
        var html = document.querySelector("html");
        var current = html.getAttribute("data-bs-theme") || "light";
        html.setAttribute("data-bs-theme", current === "dark" ? "light" : "dark");
    }
    document.getElementById("themeToggle").addEventListener("click", toggleTheme);
</script>

Detecting System Preference

// Check if the user's OS is set to dark mode
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
    document.querySelector("html").setAttribute("data-bs-theme", "dark");
}

CSS Variables — Runtime Theming

Bootstrap 5.3+ generates CSS custom properties for every component. You can override them in your stylesheet without recompiling Sass:

/* Override primary color on a specific section */
.my-section {
    --bs-primary: #e91e63;
    --bs-primary-rgb: 233, 30, 99;  /* RGB needed for rgba() operations */
}

/* Override global border radius */
:root {
    --bs-border-radius: 0.5rem;
    --bs-border-radius-lg: 1rem;
}

/* Custom card header background */
.my-card {
    --bs-card-cap-bg: #f8f9fa;
    --bs-card-border-color: #dee2e6;
}

Key CSS Variables

:root {
    /* Colors */
    --bs-primary: #0d6efd;
    --bs-primary-rgb: 13, 110, 253;
    --bs-secondary: #6c757d;
    --bs-success: #198754;

    /* Body */
    --bs-body-font-family: system-ui;
    --bs-body-font-size: 1rem;
    --bs-body-color: #212529;
    --bs-body-bg: #fff;

    /* Borders */
    --bs-border-radius: 0.375rem;
    --bs-border-color: #dee2e6;
}

Why both --bs-primary and --bs-primary-rgb? Bootstrap functions like rgba(var(--bs-primary-rgb), 0.5) need the RGB values separated. Always set both when overriding a color.

Color Modes — Custom Themes

You can create entirely custom color modes beyond light and dark:

<html data-bs-theme="custom">
[data-bs-theme="custom"] {
    --bs-body-bg: #1a1a2e;
    --bs-body-color: #e0e0e0;
    --bs-primary: #e94560;
    --bs-primary-rgb: 233, 69, 96;
    /* Override any other variable... */
}

Customization with Sass

For full control, customize Bootstrap’s Sass variables before compilation.

Setup

npm install bootstrap sass

Variable Overrides

Create a file src/custom.scss:

// 1. OVERRIDE variables BEFORE importing Bootstrap.
//    These values replace Bootstrap's defaults.
$primary: #e91e63;
$secondary: #9c27b0;
$border-radius: 0.5rem;
$enable-shadows: true;

// 2. Import Bootstrap AFTER overrides
@import "bootstrap/scss/bootstrap";

// 3. Your custom styles
.my-custom-class {
    color: $primary;
}

Build Configuration

{
    "scripts": {
        "build": "sass src/custom.scss dist/custom.css",
        "watch": "sass --watch src/custom.scss dist/custom.css"
    }
}
npm run build

Common Variables to Override

// Colors
$primary: #0d6efd;
$secondary: #6c757d;

// Typography
$font-family-sans-serif: system-ui, -apple-system, sans-serif;
$font-size-base: 1rem;

// Grid
$grid-breakpoints: (
    xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px
);
$grid-columns: 12;
$grid-gutter-width: 1.5rem;

// Components
$border-radius: 0.375rem;
$enable-shadows: false;
$enable-gradients: false;

Why override variables before importing? Bootstrap uses Sass’s !default flag on its variables. Your overrides (without !default) take priority because they’re defined first.

RTL Support — Right-to-Left Languages

Bootstrap 5 includes built-in RTL support for Arabic, Hebrew, Urdu, and other RTL scripts:

<!-- Use the RTL-specific Bootstrap CSS file -->
<html lang="ar" dir="rtl">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.rtl.min.css" rel="stylesheet">

How it works: Bootstrap uses logical properties (start/end instead of left/right). In RTL mode, start becomes right and end becomes left automatically. No class changes needed.

JavaScript Plugin API

Every interactive Bootstrap component can be controlled programmatically.

Constructor Pattern

// All components follow the same pattern:
// new bootstrap.ComponentName(element, options)

var modal = new bootstrap.Modal(element, { backdrop: "static" });
var tooltip = new bootstrap.Tooltip(element, { placement: "right" });
var popover = new bootstrap.Popover(element, { trigger: "hover" });
var toast = new bootstrap.Toast(element, { delay: 3000 });
var carousel = new bootstrap.Carousel(element, { interval: 4000 });
var offcanvas = new bootstrap.Offcanvas(element, { scroll: true });
var collapse = new bootstrap.Collapse(element, { toggle: false });
var tab = new bootstrap.Tab(element);
var dropdown = new bootstrap.Dropdown(element);
var scrollspy = new bootstrap.ScrollSpy(element, { target: "#nav" });

Static Methods — Getting Instances

// Get an existing instance (returns null if not initialized)
var modalInstance = bootstrap.Modal.getInstance(element);

// Get or create (returns existing or creates new)
var modalInstance = bootstrap.Modal.getOrCreateInstance(element, options);

// Dispose — clean up when removing elements
modalInstance.dispose();

Event Handling

Every component emits events with the .bs. namespace:

// Modal events
element.addEventListener("show.bs.modal", function(e) { /* before show */ });
element.addEventListener("shown.bs.modal", function(e) { /* after animation */ });
element.addEventListener("hide.bs.modal", function(e) { /* before hide */ });
element.addEventListener("hidden.bs.modal", function(e) { /* after close anim */ });

// Tooltip/Popover: show, shown, hide, hidden, inserted
// Toast: show, shown, hide, hidden
// Offcanvas: show, shown, hide, hidden
// Collapse: show, shown, hide, hidden
// Carousel: slide, slid
// Dropdown: show, shown, hide, hidden
// Tab: show, shown, hide, hidden

Re-initializing After Dynamic Content

When you add new elements via AJAX, tooltips/popovers/dropdowns on those elements won’t work until you initialize them:

function initDynamicComponents(container) {
    container.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(function(el) {
        new bootstrap.Tooltip(el);
    });
    container.querySelectorAll('[data-bs-toggle="popover"]').forEach(function(el) {
        new bootstrap.Popover(el);
    });
}

Comparison: CSS Variables vs Sass Variables

FeatureCSS VariablesSass Variables
When they existRuntime (in browser)Build time (in .css file)
Can change dynamically?Yes (via JS)No (fixed after compile)
Browser supportModern browsersAll (compiled to static values)
ThemingRuntime theme switchingPre-built theme files
PerformanceSlightly slower (browser resolves)Faster (pre-computed)

Common Mistakes

1. Not re-initializing components after AJAX

Dynamically loaded content with data-bs-toggle="tooltip" won’t work unless you call new bootstrap.Tooltip(el) after insertion.

2. Forgetting the -rgb variant when overriding colors

Setting --bs-primary: #e91e63 without --bs-primary-rgb: 233, 30, 99 breaks components that use rgba(var(--bs-primary-rgb), 0.5) for transparency.

3. Using data attributes and JS API on the same component

If you initialize a modal with data-bs-toggle and also with new bootstrap.Modal(), they can conflict. Use one approach.

4. Not escaping Sass variables in custom selectors

// WRONG — Sass tries to interpret $btn-color as a variable
.btn-custom { color: $btn-color; }
// RIGHT — use interpolation
.btn-custom { color: #{$btn-color}; }

5. Using standard bootstrap.min.css for RTL layouts

The standard CSS is LTR-only. RTL layouts need bootstrap.rtl.min.css and dir="rtl" on <html>.

Practice Questions

  1. How does data-bs-theme="dark" work at the component level? Answer: It overrides the CSS variables for that component and its children only. Components outside it use the page’s theme (or default to light).

  2. What’s the difference between Bootstrap 5’s CSS variables and Sass variables? Answer: CSS variables exist at runtime and can be changed dynamically via JavaScript. Sass variables are compiled to static values in the .css file and can’t change at runtime.

  3. Why do you override Sass variables BEFORE importing Bootstrap? Answer: Bootstrap uses !default on its variables. Your override (without !default) takes precedence because it’s defined first. If you import first, your override becomes the default and Bootstrap’s value wins.

  4. How do you dispose of a tooltip before removing its trigger element from the DOM? Answer: Call bootstrap.Tooltip.getInstance(element).dispose() to remove event listeners and prevent memory leaks.

  5. What does the slide.bs.carousel event indicate? Answer: It fires immediately when a slide transition starts (before the new slide is visible). Use it to pause video players or analytics tracking.

Challenge: Create a theme switcher page with 3 theme buttons (Light, Dark, Custom) that change data-bs-theme on the <html>. The “Custom” theme should use a purple color scheme with a dark background. Include cards, buttons, and a table that all respond to theme changes.

FAQ

How do I enable dark mode in Bootstrap 5.3+?
Add data-bs-theme="dark" to the <html> element. Toggle it with JavaScript to switch between light and dark.
Can I have dark mode only on certain components?
Yes, add data-bs-theme="dark" to any individual component like <div class="card" data-bs-theme="dark">.
What is the difference between Bootstrap’s CSS variables and Sass variables?
Sass variables exist only at build time. CSS variables exist at runtime and can be changed dynamically. Bootstrap 5.3+ uses CSS variables for components, making runtime theming possible.
How do I customize Bootstrap without compiling Sass?
Override CSS variables in your stylesheet: :root { --bs-primary: #e91e63; }. This works for Bootstrap 5.3+ but may not cover everything.
Do I need jQuery for Bootstrap 5?
No. Bootstrap 5 uses vanilla JavaScript. jQuery was removed in Bootstrap 5.
How do I create a custom build of Bootstrap?
Install bootstrap and sass via npm, create a .scss file with variable overrides before @import "bootstrap/scss/bootstrap", and compile with sass.

Try It Yourself

<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Theme Switcher</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container py-5">
        <div class="d-flex justify-content-between align-items-center mb-4">
            <h1>Theme Switcher Demo</h1>
            <div class="d-flex align-items-center gap-2">
                <span class="form-check-label" id="themeLabel">Light</span>
                <div class="form-check form-switch mb-0">
                    <input class="form-check-input" type="checkbox" role="switch" id="darkSwitch" style="cursor:pointer;">
                </div>
            </div>
        </div>

        <div class="row g-4">
            <div class="col-md-4">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">Responsive Card</h5>
                        <p class="card-text">This card responds to theme changes.</p>
                        <button class="btn btn-primary">Primary Button</button>
                        <button class="btn btn-outline-secondary">Secondary</button>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card" data-bs-theme="dark">
                    <div class="card-body">
                        <h5 class="card-title">Always Dark</h5>
                        <p class="card-text">This card ignores global theme.</p>
                        <button class="btn btn-primary">Primary</button>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card" data-bs-theme="light">
                    <div class="card-body">
                        <h5 class="card-title">Always Light</h5>
                        <p class="card-text">This card ignores global theme.</p>
                        <button class="btn btn-primary">Primary</button>
                    </div>
                </div>
            </div>
        </div>

        <div class="mt-4">
            <div class="alert alert-info">
                <strong>Demo:</strong> Toggle the switch to change the page theme.
                The "Always Dark" and "Always Light" cards ignore the global theme.
            </div>
        </div>

        <div class="table-responsive mt-4">
            <table class="table table-striped">
                <thead class="table-dark">
                    <tr><th>Feature</th><th>Value</th></tr>
                </thead>
                <tbody>
                    <tr><td>Framework</td><td>Bootstrap 5.3+</td></tr>
                    <tr><td>Color Mode</td><td id="currentMode">Light</td></tr>
                </tbody>
            </table>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        var html = document.querySelector("html");
        var toggle = document.getElementById("darkSwitch");
        var label = document.getElementById("themeLabel");
        var modeDisplay = document.getElementById("currentMode");

        toggle.addEventListener("change", function() {
            var isDark = this.checked;
            html.setAttribute("data-bs-theme", isDark ? "dark" : "light");
            label.textContent = isDark ? "Dark" : "Light";
            modeDisplay.textContent = isDark ? "Dark" : "Light";
        });
    </script>
</body>
</html>

This sandbox demonstrates: dark mode toggle, per-component theme override, responsive layout, and JavaScript-driven theme switching.

What’s Next

TopicDescription
Bootstrap ReferenceComplete cheatsheet of all classes
SassLearn the CSS preprocessor used by Bootstrap
JavaScript APIDeep dive into JavaScript event handling
CSS Custom PropertiesUnderstanding CSS variables in depth

What’s Next

Congratulations on completing this Bootstrap Advanced tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro