Bootstrap 5.3.8 is the most popular HTML, CSS, and JS front-end framework for responsive, mobile-first web development. This guide covers the architecture, build system, configuration surface, deployment strategies, and internal design patterns that administrators, integrators, and contributing developers need to operate and extend Bootstrap effectively.
- Version: 5.3.8
- License: MIT
- Authors: Mark Otto, Jacob Thornton, and contributors
- Repository: github.com/twbs/bootstrap
- Homepage: getbootstrap.com
- Peer Dependency:
@popperjs/core^2.11.8
For installation walkthroughs, component usage examples, and everyday development tasks, see the companion User Guide.
1. Architecture Overview
1.1 High-Level Layer Diagram
┌─────────────────────────────────────────────────────────┐
│ Consumer Code │
│ (HTML markup + data-bs-* attributes) │
├─────────────────────────────────────────────────────────┤
│ Entry Points │
│ js/index.esm.js (ES modules) js/index.umd.js (UMD) │
├─────────────────────────────────────────────────────────┤
│ Plugin Components │
│ Alert │ Button │ Carousel │ Collapse │ Dropdown │ Modal │
│ Offcanvas │ ScrollSpy │ Tab │ Toast │ Tooltip │Popover │
├─────────────────────────────────────────────────────────┤
│ BaseComponent (base-component.js) │
│ VERSION = '5.3.8' │
├─────────────────────────────────────────────────────────┤
│ Config (config.js) base class │
├────────────────┬────────────────────────────────────────┤
│ DOM Layer │ Utility Layer │
│ data.js │ backdrop.js focustrap.js │
│ event-handler │ sanitizer.js scrollbar.js │
│ manipulator │ swipe.js template-factory.js │
│ selector-eng │ component-functions.js index.js │
├────────────────┴────────────────────────────────────────┤
│ SCSS Layer │
│ scss/bootstrap.scss → _variables → _maps → _mixins │
│ → _root → _reboot → component partials → _utilities │
├─────────────────────────────────────────────────────────┤
│ Build Tooling │
│ Sass → PostCSS/Autoprefixer → RTLCSS → clean-css │
│ Rollup → Babel → Terser │
│ Astro 5.18.1 (docs site SSG) │
└─────────────────────────────────────────────────────────┘
1.2 Component Inventory
| Component | Source File | Dependencies | Default Config Keys |
|---|---|---|---|
| Alert | js/src/alert.js |
— | — |
| Button | js/src/button.js |
— | — |
| Carousel | js/src/carousel.js |
Swipe | interval, keyboard, pause, ride, touch, wrap |
| Collapse | js/src/collapse.js |
— | parent, toggle |
| Dropdown | js/src/dropdown.js |
Popper | autoClose, boundary, display, offset, popperConfig, reference |
| Modal | js/src/modal.js |
Backdrop, FocusTrap, ScrollBarHelper | backdrop, focus, keyboard |
| Offcanvas | js/src/offcanvas.js |
Backdrop, FocusTrap, ScrollBarHelper | backdrop, keyboard, scroll |
| Popover | js/src/popover.js |
(inherits Tooltip) | (extends Tooltip defaults) |
| ScrollSpy | js/src/scrollspy.js |
— | — |
| Tab | js/src/tab.js |
— | — |
| Toast | js/src/toast.js |
— | — |
| Tooltip | js/src/tooltip.js |
Popper, TemplateFactory, Sanitizer | — |
1.3 Class Hierarchy
Config (base) ← js/src/util/config.js
├── Backdrop ← js/src/util/backdrop.js
├── FocusTrap ← js/src/util/focustrap.js
├── Swipe ← js/src/util/swipe.js
├── TemplateFactory ← js/src/util/template-factory.js
└── BaseComponent ← js/src/base-component.js (VERSION = '5.3.8')
├── Alert
├── Button
├── Carousel
├── Collapse
├── Dropdown (uses Popper)
├── Modal (uses Backdrop, FocusTrap, ScrollBarHelper)
├── Offcanvas (uses Backdrop, FocusTrap, ScrollBarHelper)
├── ScrollSpy
├── Tab
├── Toast
└── Tooltip (uses Popper, TemplateFactory, Sanitizer)
└── Popover
ScrollBarHelper ← js/src/util/scrollbar.js (standalone, no parent)
1.4 Data Flow: Component Initialization
1. DOM ready (or explicit JS call)
2. new ComponentClass(element, config)
3. Config._mergeConfigObj() resolves final config:
Default values
↓ override with data-bs-config='{...}' JSON attribute
↓ override with individual data-bs-{key} attributes
↓ override with JS config object
4. Config._typeCheckConfig() validates types against DefaultType
5. BaseComponent constructor:
a. Stores instance in DOM data store (data.js Map)
b. Registers event listeners via EventHandler
6. Component-specific setup (show/hide state, Popper init, etc.)
1.5 Technology Stack
| Layer | Technology | Version Constraint |
|---|---|---|
| CSS preprocessor | Dart Sass | (see dart-sass compatibility notes) |
| CSS post-processing | PostCSS + Autoprefixer | — |
| RTL generation | RTLCSS | — |
| CSS minification | clean-css | — |
| JS bundler | Rollup | — |
| JS transpiler | Babel | — |
| JS minifier | Terser | — |
| Docs site | Astro (SSG) | 5.18.1 |
| JS testing | Jasmine + Karma | Chrome launcher |
| SCSS testing | sass-true + Jasmine | — |
| Linting | ESLint, Stylelint, Prettier, lockfile-lint | — |
| HTML validation | vnu-jar | — |
| Responsive font sizes | RFS | v10.0.0 |
2. System Requirements
2.1 Build Environment
| Requirement | Detail |
|---|---|
| Node.js | Required for all build tasks and docs site |
| npm | Package manager (lockfile-lint enforced) |
| Dart Sass | SCSS compilation (sass npm package) |
| Git | Repository management |
Note
Bootstrap is a front-end framework delivered as CSS and JS. Node.js is only required if you are building from source, customizing Sass variables, or running the docs site locally. End users consuming CDN or prebuilt dist files do not need Node.js.
2.2 Browser Support
Bootstrap targets modern browsers as defined in .browserslistrc. The framework does not support Internet Explorer. All current stable versions of Chrome, Firefox, Safari, Edge, and their mobile counterparts are supported.
2.3 Sass Requirements
When compiling SCSS from source, ensure your Sass compiler supports the features used by Bootstrap 5.3.8.
Warning
Dart Sass 1.80.0+ emits deprecation warnings for certain patterns used in Bootstrap (see #40962). These are warnings only and do not affect output. Pin your Sass version or suppress warnings if they clutter your build log.
2.4 Popper.js Dependency
Dropdown, Tooltip, and Popover require @popperjs/core ^2.11.8 for positioning. If you use bootstrap.bundle.js or bootstrap.bundle.min.js, Popper is included. If you use the standalone build (bootstrap.js or bootstrap.esm.js), you must provide Popper separately.
3. Configuration Reference
3.1 Sass Variables — Theme Colors
Override these in your custom Sass file before importing Bootstrap:
// _variables.scss defaults
$primary: #0d6efd;
$secondary: #6c757d;
$success: #28a745;
$danger: #dc3545;
$warning: #ffc107;
$info: #17a2b8;
$light: #f8f9fa;
$dark: #343a40;
The $theme-colors map collects these into a single map used by the utilities API, component styles, and CSS custom properties.
3.2 Sass Variables — Base Colors
$blue: #0d6efd;
$indigo: #6610f2;
$purple: #6f42c1;
$pink: #d63384;
$red: #dc3545;
$orange: #fd7e14;
$yellow: #ffc107;
$green: #198754;
$teal: #20c997;
$cyan: #0dcaf0;
$white: #fff;
$gray: #6c757d;
$gray-dark: #343a40;
3.3 Sass Variables — Gray Scale
| Variable | Value |
|---|---|
$gray-100 |
#f8f9fa |
$gray-200 |
#e9ecef |
$gray-300 |
#dee2e6 |
$gray-400 |
#ced4da |
$gray-500 |
#adb5bd |
$gray-600 |
#868e96 |
$gray-700 |
#495057 |
$gray-800 |
#343a40 |
$gray-900 |
#212529 |
3.4 Sass Variables — Breakpoints
| Breakpoint | Variable | Min-width | Container Max-width |
|---|---|---|---|
| xs | $grid-breakpoint-xs |
0 | (none — fluid) |
| sm | $grid-breakpoint-sm |
576px | 540px |
| md | $grid-breakpoint-md |
768px | 720px |
| lg | $grid-breakpoint-lg |
992px | 960px |
| xl | $grid-breakpoint-xl |
1200px | 1140px |
| xxl | $grid-breakpoint-xxl |
1400px | 1320px |
The $grid-breakpoints and $container-max-widths maps are the canonical sources for these values. Override the map itself to add, remove, or change breakpoints.
3.5 Sass Variables — Spacing
The spacing scale is derived from $spacer (default 1rem) and the $spacers map:
| Key | Value |
|---|---|
| 0 | 0 |
| 1 | $spacer * 0.25 |
| 2 | $spacer * 0.5 |
| 3 | $spacer |
| 4 | $spacer * 1.5 |
| 5 | $spacer * 3 |
3.6 Sass Variables — Typography
Key typography variables include $font-family-sans-serif, $font-family-monospace, $font-size-base (default 1rem), $font-size-lg, $font-size-sm, $line-height-base (default 1.5), $headings-font-weight (default 500), and the heading size scale ($h1-font-size through $h6-font-size).
3.7 Sass Maps
Bootstrap uses Sass maps extensively. The key maps to know:
| Map | Purpose | Location |
|---|---|---|
$theme-colors |
All theme color values | _variables.scss |
$grays |
Gray scale values | _variables.scss |
$grid-breakpoints |
Responsive breakpoints | _variables.scss |
$container-max-widths |
Max container widths per breakpoint | _variables.scss |
$spacers |
Spacing scale | _variables.scss |
$utilities |
Utility class definitions | _utilities.scss → utilities/_api.scss |
Maps are merged and finalized in scss/_maps.scss. Override variables before the import chain; modify maps in _maps.scss or after it.
3.8 CSS Custom Properties
Bootstrap generates CSS custom properties (CSS variables) in :root via scss/_root.scss. These include all theme colors, body defaults, font families, and component-level tokens. Dark mode overrides these properties under [data-bs-theme="dark"].
3.9 Color Mode Configuration
Bootstrap 5.3 supports light and dark color modes via the data-bs-theme attribute:
<!-- Set on <html> for global dark mode -->
<html data-bs-theme="dark">
<!-- Set on a container for scoped dark mode -->
<div data-bs-theme="dark">
<!-- Dark-themed content -->
</div>
Dark-mode variables are defined in scss/_variables-dark.scss. The color-mode mixin (scss/mixins/_color-mode.scss) generates the [data-bs-theme="dark"] selector rules.
Important
Dark mode applies through CSS custom property overrides, not by generating a separate stylesheet. This means a single CSS file supports both modes. Switching modes at runtime is a matter of changing the
data-bs-themeattribute value via JavaScript.
3.10 Utilities API Configuration
The utilities API (scss/utilities/_api.scss) generates utility classes from the $utilities map. Each utility entry defines:
| Key | Type | Description |
|---|---|---|
property |
string/list | The CSS property (or properties) to set |
values |
map/list | The values to generate classes for |
class |
string | Class prefix (defaults to property name) |
responsive |
boolean | Generate responsive variants (-sm, -md, etc.) |
rfs |
boolean | Apply RFS (responsive font sizing) |
print |
boolean | Generate print variants |
state |
string | Generate pseudo-class variants (e.g., hover) |
css-var |
boolean | Output as CSS custom property instead of property |
css-variable-name |
string | Override the CSS variable name |
local-vars |
map | Additional local CSS variables |
Add, modify, or remove utilities by manipulating the $utilities map after Bootstrap's default import.
3.11 Component Default Configs (JS)
These are the default configuration objects for JavaScript-driven components. Override via data-bs-* attributes or the JS constructor's config parameter.
Carousel:
| Option | Type | Default | Description |
|---|---|---|---|
interval |
number | 5000 |
Auto-cycling delay in ms |
keyboard |
boolean | true |
React to keyboard events |
pause |
string/false | 'hover' |
Pause on mouseenter |
ride |
string/false | false |
Auto-start cycling |
touch |
boolean | true |
Enable touch swipe |
wrap |
boolean | true |
Continuous cycling |
Collapse:
| Option | Type | Default | Description |
|---|---|---|---|
parent |
string/element/false | null |
Accordion parent selector |
toggle |
boolean | true |
Toggle on initialization |
Dropdown:
| Option | Type | Default | Description |
|---|---|---|---|
autoClose |
boolean/string | true |
Close behavior |
boundary |
string/element | 'clippingParents' |
Overflow boundary for Popper |
display |
string | 'dynamic' |
Popper positioning ('dynamic' or 'static') |
offset |
array/function | [0, 2] |
[skidding, distance] |
popperConfig |
object/function/null | null |
Custom Popper config |
reference |
string/element/object | 'toggle' |
Reference element for Popper |
Modal:
| Option | Type | Default | Description |
|---|---|---|---|
backdrop |
boolean/string | true |
Include backdrop ('static' prevents close on click) |
focus |
boolean | true |
Focus modal on open |
keyboard |
boolean | true |
Close on Escape key |
Offcanvas:
| Option | Type | Default | Description |
|---|---|---|---|
backdrop |
boolean | true |
Show backdrop |
keyboard |
boolean | true |
Close on Escape key |
scroll |
boolean | false |
Allow body scrolling while open |
Backdrop Utility:
| Option | Type | Default |
|---|---|---|
className |
string | 'modal-backdrop' |
clickCallback |
function/null | null |
isAnimated |
boolean | false |
isVisible |
boolean | true |
rootElement |
string/element | 'body' |
FocusTrap Utility:
| Option | Type | Default |
|---|---|---|
autofocus |
boolean | true |
trapElement |
element/null | null |
4. Deployment & Scaling
4.1 CDN Deployment
The fastest path to production. Include the prebuilt CSS and JS from a CDN (jsDelivr, cdnjs, unpkg):
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Use SRI (Subresource Integrity) hashes for security — see Section 7.3.
4.2 Self-Hosting
Copy the dist/ directory contents to your static asset server. The dist/ contains:
dist/
├── css/
│ ├── bootstrap.css (+ .map)
│ ├── bootstrap.min.css (+ .map)
│ ├── bootstrap.rtl.css (+ .map)
│ ├── bootstrap.rtl.min.css (+ .map)
│ ├── bootstrap-grid.css (+ .min.css variants)
│ ├── bootstrap-reboot.css (+ .min.css variants)
│ └── bootstrap-utilities.css (+ .min.css variants)
└── js/
├── bootstrap.js (+ .map)
├── bootstrap.min.js (+ .map)
├── bootstrap.esm.js (+ .map)
├── bootstrap.esm.min.js (+ .map)
├── bootstrap.bundle.js (+ .map, includes Popper)
└── bootstrap.bundle.min.js (+ .map, includes Popper)
4.3 Package Manager Integration
npm:
npm install bootstrap@5.3.8
Key fields in package.json:
| Field | Value | Purpose |
|---|---|---|
main |
dist/js/bootstrap.js |
CommonJS/UMD entry |
module |
dist/js/bootstrap.esm.js |
ES module entry |
sass |
scss/bootstrap.scss |
Sass entry |
style |
dist/css/bootstrap.css |
Pre-compiled CSS |
Published files include dist/{css,js}/*.{css,js,map}, js/{src,dist}/**/*.{js,map}, js/index.{esm,umd}.js, and scss/**/*.scss (excluding scss/tests).
Composer (PHP):
composer require twbs/bootstrap:5.3.8
Package name: twbs/bootstrap
NuGet (.NET):
Two packages available:
bootstrap— compiled CSS and JSbootstrap.sass— Sass source files
Meteor.js:
meteor add twbs:bootstrap
4.4 Subset Builds
Bootstrap provides focused subsets for minimal footprints:
| Subset | Entry File | Purpose | Max Gzipped Size |
|---|---|---|---|
| Grid only | scss/bootstrap-grid.scss |
Grid + flexbox utilities | 6.0 kB |
| Reboot only | scss/bootstrap-reboot.scss |
Normalize + reboot | 3.25 kB |
| Utilities only | scss/bootstrap-utilities.scss |
All utility classes | 10.75 kB |
4.5 Custom Sass Builds
Create a custom entry file that imports only what you need:
// custom.scss — import only needed components
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
// Only the components you use:
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api"; // Must be last — generates utility classes
4.6 Production Optimization
Tip
For production builds, combine a custom Sass import with PurgeCSS (or your bundler's tree-shaking) to eliminate unused CSS. Bootstrap's full minified CSS is 30.25 kB gzipped — a selective import plus PurgeCSS can reduce this to under 10 kB for typical projects.
Bundle size budget:
| File | Max Gzipped Size |
|---|---|
bootstrap.min.css |
30.25 kB |
bootstrap.min.js |
16.25 kB |
bootstrap.bundle.min.js |
23.5 kB |
bootstrap.esm.min.js |
18.25 kB |
bootstrap-grid.min.css |
6.0 kB |
bootstrap-reboot.min.css |
3.25 kB |
bootstrap-utilities.min.css |
10.75 kB |
5. Operations
5.1 Build System — npm Scripts Reference
All build orchestration runs through npm scripts defined in package.json.
Top-Level Commands
| Command | Description |
|---|---|
npm start |
Run parallel watchers + docs site dev server |
npm run dist |
Build CSS and JS in parallel (production) |
npm test |
Full test suite: lint + dist + JS tests + docs build + docs lint |
npm run release |
Full release: dist + SRI hashes + docs build + zip |
npm run lint |
Run all linters (JS + CSS + lockfile) |
npm run watch |
Parallel watchers for CSS (main, dist, docs, test) and JS (main, docs) |
CSS Commands
| Command | Description |
|---|---|
npm run css |
Full CSS pipeline: compile + prefix + RTL + minify |
npm run css-compile |
sass --style expanded --source-map --embed-sources --no-error-css scss/:dist/css/ |
npm run css-rtl |
Generate RTL variants via PostCSS with RTLCSS |
npm run css-lint |
Stylelint + find-unused-sass-variables |
npm run css-test |
Sass unit tests via jasmine --config=scss/tests/jasmine.js |
npm run css-minify |
Minify CSS output with clean-css |
JS Commands
| Command | Description |
|---|---|
npm run js |
Full JS pipeline: compile + minify |
npm run js-compile |
Rollup builds (standalone, standalone-esm, bundle, plugins) |
npm run js-lint |
ESLint |
npm run js-test |
Karma tests + jQuery integration tests + integration tests |
npm run js-debug |
Run Karma tests with DEBUG=true |
npm run js-minify |
Minify JS output with Terser |
Docs Commands
| Command | Description |
|---|---|
npm run docs |
Build docs + lint |
npm run docs-build |
astro build --root site |
npm run docs-serve |
astro dev --root site --port 9001 |
5.2 Watch Mode
npm run watch starts six parallel watchers:
- css-main — recompiles main SCSS on changes
- css-dist — recompiles distribution CSS
- css-docs — recompiles docs-specific CSS
- css-test — reruns SCSS tests
- js-main — rebuilds main JS bundle
- js-docs — rebuilds docs JS
npm start combines watch mode with docs-serve for a full local development environment at http://localhost:9001.
5.3 Docs Site Local Development
The documentation site is built with Astro 5.18.1 as a static site generator:
# Install dependencies
npm install
# Start docs dev server on port 9001
npm run docs-serve
# Build static docs site
npm run docs-build
The site source lives under site/:
| Directory | Content |
|---|---|
site/astro.config.ts |
Astro configuration |
site/data/*.yml |
Data files (breakpoints, colors, team, versions, sidebar, etc.) |
site/src/content/docs/ |
MDX documentation pages |
site/src/components/ |
Astro components (shortcodes, header, footer, icons) |
site/src/layouts/ |
Page layouts (Base, Docs, Examples, Redirect, Single) |
site/src/libs/ |
TypeScript utilities (config, content, data, toc, prism, etc.) |
site/src/pages/ |
Astro route pages |
Site configuration values from config.yml:
| Key | Value |
|---|---|
current_version |
5.3.8 |
docs_version |
5.3 |
rfs_version |
v10.0.0 |
algolia.app_id |
AK7KMZKZHQ |
algolia.index |
bootstrap |
analytics.fathom |
ITUSEYJG |
5.4 Release Process
The npm run release script executes:
npm run dist— build all CSS and JSrelease-sri— generate Subresource Integrity hashesnpm run docs-build— build the documentation siterelease-zip— package distribution files into a zip archive
6. Performance
6.1 Bundle Size Analysis
Bootstrap's distribution files are size-checked as part of the build process:
| File | Max Gzipped Size |
|---|---|
bootstrap.min.css |
30.25 kB |
bootstrap.min.js |
16.25 kB |
bootstrap.bundle.min.js (includes Popper) |
23.5 kB |
bootstrap.esm.min.js |
18.25 kB |
bootstrap-grid.min.css |
6.0 kB |
bootstrap-reboot.min.css |
3.25 kB |
bootstrap-utilities.min.css |
10.75 kB |
6.2 Tree-Shaking Individual JS Components
The ES module entry (js/index.esm.js) exports all 12 plugin components individually. Modern bundlers (Webpack 4+, Rollup, Vite) can tree-shake unused exports:
// Only imports Tooltip and Modal — bundler eliminates the rest
import { Tooltip, Modal } from 'bootstrap';
For maximum control, import directly from source:
import Tooltip from 'bootstrap/js/src/tooltip';
import Modal from 'bootstrap/js/src/modal';
6.3 CSS Optimization with PurgeCSS
Bootstrap generates utility classes for every value in every configured map. Most projects use a fraction of these. Integrate PurgeCSS (or Tailwind CSS's JIT-like approach) into your build pipeline:
// postcss.config.js example
module.exports = {
plugins: [
require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.html', './src/**/*.js'],
safelist: {
// Keep dynamically-added classes
greedy: [/^modal/, /^tooltip/, /^popover/, /^offcanvas/]
}
})
]
};
Caution
PurgeCSS can remove classes that are added dynamically by JavaScript components (e.g.,
modal-backdrop,show,fade,collapsing). Always safelist class patterns for any Bootstrap JS component you use.
6.4 RFS (Responsive Font Sizes)
Bootstrap uses RFS v10.0.0 to scale font sizes and spacing values responsively. RFS converts px or rem values into a calc() expression that scales between a minimum and maximum viewport width. This is applied automatically to heading sizes and can be enabled for any utility via the rfs: true flag in the utilities API.
6.5 Import Strategies
| Strategy | CSS Size Impact | JS Size Impact | Best For |
|---|---|---|---|
| Full CDN | 30.25 kB CSS + 23.5 kB JS | None | Prototyping, small sites |
| Custom Sass imports | 40-80% reduction | N/A | Production sites with build step |
| Custom Sass + PurgeCSS | 70-95% reduction | N/A | Performance-critical sites |
| ES module tree-shaking | N/A | 30-70% reduction | SPAs, apps using few components |
| Subset builds (grid/reboot/utilities) | 80-90% reduction | N/A | Utility-focused projects |
7. Security
7.1 HTML Sanitizer (Tooltip & Popover)
Bootstrap includes a built-in HTML sanitizer (js/src/util/sanitizer.js) that filters content passed to Tooltip and Popover components. This prevents XSS attacks when content is sourced from user input or untrusted data.
The sanitizer maintains an allowlist of safe HTML elements and attributes. Content not matching the allowlist is stripped before insertion into the DOM.
Warning
The built-in sanitizer provides defense-in-depth but should not be your only XSS prevention layer. Always sanitize user input server-side before it reaches the client. If you pass content via the
html: trueoption and a customsanitizeFn, ensure your custom function is at least as strict as the default.
7.2 XSS Prevention Patterns
- Data attributes: Values read from
data-bs-*attributes are treated as configuration, not raw HTML. The Manipulator module (js/src/dom/manipulator.js) handles type coercion. - Template rendering: The TemplateFactory (
js/src/util/template-factory.js) used by Tooltip and Popover sanitizes HTML content before DOM insertion. - Event system: Bootstrap's custom event system (
js/src/dom/event-handler.js) does not evaluate string content as code.
7.3 Subresource Integrity (SRI)
When loading Bootstrap from a CDN, use SRI hashes to ensure the file has not been tampered with:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-HASH_HERE"
crossorigin="anonymous">
SRI hashes are generated during the release process (release-sri npm script) and published on the Bootstrap website.
7.4 Content Security Policy Considerations
Bootstrap's CSS uses inline styles for certain dynamic operations (e.g., Carousel slide positioning, progress bar widths). If your CSP disallows style-src 'unsafe-inline', you will need to either:
- Use a nonce-based CSP and inject the nonce into Bootstrap's style operations
- Use CSS custom properties for dynamic values instead of inline styles
- Whitelist specific hashes for Bootstrap's known inline style patterns
Bootstrap's JavaScript does not use eval() or new Function(), so script-src 'unsafe-eval' is not required.
8. Developer Internals
8.1 Repository Structure
twbs/bootstrap/ (657 files, 284,276 source chars)
├── js/
│ ├── index.esm.js ES module entry (exports all 12 plugins)
│ ├── index.umd.js UMD entry (exports as `bootstrap` global)
│ └── src/
│ ├── alert.js Alert plugin
│ ├── base-component.js BaseComponent (VERSION = '5.3.8')
│ ├── button.js Button plugin
│ ├── carousel.js Carousel plugin
│ ├── collapse.js Collapse plugin
│ ├── dropdown.js Dropdown plugin (uses Popper)
│ ├── modal.js Modal plugin
│ ├── offcanvas.js Offcanvas plugin
│ ├── popover.js Popover plugin (extends Tooltip)
│ ├── scrollspy.js ScrollSpy plugin
│ ├── tab.js Tab plugin
│ ├── toast.js Toast plugin
│ ├── tooltip.js Tooltip plugin (uses Popper)
│ ├── dom/ DOM abstraction layer
│ │ ├── data.js Per-element data storage (Map-based)
│ │ ├── event-handler.js Event system (namespacing, delegation)
│ │ ├── manipulator.js Data-attribute reading/writing
│ │ └── selector-engine.js querySelector wrappers
│ └── util/ Utility modules
│ ├── index.js Common utility functions
│ ├── config.js Config base class
│ ├── backdrop.js Backdrop class
│ ├── component-functions.js enableDismissTrigger
│ ├── focustrap.js FocusTrap class
│ ├── sanitizer.js HTML sanitizer
│ ├── scrollbar.js ScrollBarHelper
│ ├── swipe.js Touch swipe detection
│ └── template-factory.js Template rendering
├── scss/
│ ├── bootstrap.scss Main entry
│ ├── bootstrap-grid.scss Grid-only subset
│ ├── bootstrap-reboot.scss Reboot-only subset
│ ├── bootstrap-utilities.scss Utilities-only subset
│ ├── _variables.scss All Sass variables
│ ├── _variables-dark.scss Dark mode variable overrides
│ ├── _maps.scss Sass map finalization
│ ├── _mixins.scss Mixin imports
│ ├── _functions.scss Sass functions
│ ├── _root.scss CSS custom properties
│ ├── _reboot.scss Normalize/reboot
│ ├── _utilities.scss Utility definitions
│ ├── forms/ Form component partials (8 files)
│ ├── helpers/ Helper partials (12 files)
│ ├── mixins/ Mixin partials (24 files)
│ ├── utilities/
│ │ └── _api.scss Utility class generator
│ └── tests/ Sass unit tests
├── site/ Astro docs site
│ ├── astro.config.ts
│ ├── data/ YAML data files
│ ├── src/
│ │ ├── content/docs/ MDX documentation
│ │ ├── components/ Astro components
│ │ ├── layouts/ Page layouts
│ │ ├── libs/ TypeScript utilities
│ │ └── pages/ Route pages
├── build/ Build scripts (Rollup, plugins)
├── dist/ Compiled output (CSS + JS)
└── nuget/ NuGet package specs
8.2 Class Hierarchy Deep Dive
Config Base Class (js/src/util/config.js)
Every configurable component extends Config. It provides:
static get Default— returns the default config objectstatic get DefaultType— returns type constraints (used for validation)static get NAME— component name (must be implemented by subclasses; throwsError: You have to implement the static method "NAME"if missing)_mergeConfigObj(config, element)— merges config from multiple sources_typeCheckConfig(config)— validates each config key againstDefaultType
Configuration Merge Pipeline
The _mergeConfigObj method resolves the final configuration through a 4-layer override chain:
Layer 1: Static Default object (lowest priority)
↓
Layer 2: data-bs-config='{"key": "value"}' JSON attribute on the element
↓
Layer 3: Individual data-bs-{key} attributes on the element
↓
Layer 4: JavaScript config object passed to constructor (highest priority)
Note
The
data-bs-configJSON attribute provides a way to set multiple options in a single attribute. Individualdata-bs-*attributes override keys fromdata-bs-config. The JS constructor config overrides everything.
BaseComponent (js/src/base-component.js)
Extends Config. Every visible plugin extends BaseComponent, which provides:
- Constructor: stores the component instance in the DOM data store (
data.js) keyed by element + component name dispose()— removes event listeners and clears stored datastatic getInstance(element)— retrieves existing instance from data storestatic getOrCreateInstance(element, config)— get or create with lazy initstatic get VERSION— returns'5.3.8'
Plugin Pattern
Each plugin follows a consistent structure:
class ComponentName extends BaseComponent {
static get Default() { return { /* ... */ } }
static get DefaultType() { return { /* ... */ } }
static get NAME() { return 'componentName' }
// Public API
show() { /* ... */ }
hide() { /* ... */ }
toggle() { /* ... */ }
dispose() { /* ... */ }
// Private implementation
_method() { /* ... */ }
// Static: jQuery interface + data-api event binding
static jQueryInterface(config) { /* ... */ }
}
8.3 DOM Layer
data.js — Per-Element Data Storage
Uses a Map keyed by DOM element to store component instances. This replaces jQuery's .data() method with a framework-agnostic approach. Each element can hold one instance per component type.
event-handler.js — Custom Event System
Features:
- Namespacing: events are namespaced as
{event}.bs.{component}(e.g.,show.bs.modal,hidden.bs.collapse) - Event delegation: supports delegated event listeners via selector parameter
- One-off listeners:
one()method for single-execution handlers - Custom events: Bootstrap fires custom events that are cancelable — calling
event.preventDefault()onshoworhideevents stops the operation
Standard event lifecycle for visibility-toggling components:
| Event | When Fired | Cancelable |
|---|---|---|
show.bs.{component} |
Before showing | Yes |
shown.bs.{component} |
After shown (transition complete) | No |
hide.bs.{component} |
Before hiding | Yes |
hidden.bs.{component} |
After hidden (transition complete) | No |
Additional component-specific events:
- Modal:
hidePrevented.bs.modal(when static backdrop prevents close) - Carousel:
slide.bs.carousel,slid.bs.carousel
manipulator.js — Data Attribute Reading
Reads and writes data-bs-* attributes with automatic type coercion (strings "true"/"false" become booleans, numeric strings become numbers).
selector-engine.js — Query Wrappers
Provides querySelector and querySelectorAll wrappers, plus getElementFromSelector() which resolves the target element from data-bs-target or href attributes.
8.4 Utility Layer
index.js — Common Utilities
Key exported functions:
| Function | Purpose |
|---|---|
parseSelector |
Parse and escape selector strings |
toType |
Reliable type checking (replaces typeof) |
getUID |
Generate unique IDs |
getTransitionDurationFromElement |
Read CSS transition duration |
triggerTransitionEnd |
Force transition end dispatch |
isElement |
Check if value is a DOM element |
getElement |
Resolve selector string to element |
isVisible |
Check element visibility |
isDisabled |
Check disabled state |
findShadowRoot |
Find shadow DOM root |
noop |
No-operation function |
reflow |
Force browser reflow |
getjQuery |
Detect jQuery presence |
onDOMContentLoaded |
Safe DOMContentLoaded handler |
isRTL |
Check dir="rtl" on <html> |
defineJQueryPlugin |
Register plugin with jQuery |
execute |
Execute function or return value |
executeAfterTransition |
Run callback after CSS transition |
getNextActiveElement |
Cycle through element list |
backdrop.js
Manages the semi-transparent overlay for Modal and Offcanvas. Config: className, clickCallback, isAnimated, isVisible, rootElement.
focustrap.js
Traps keyboard focus within Modal and Offcanvas containers. Listens for focusin events and redirects focus back to the trap element when focus escapes. Config: autofocus, trapElement.
sanitizer.js
Provides HTML sanitization for Tooltip and Popover content. Maintains an allowlist of safe elements and attributes. Custom sanitizer functions can be provided via the sanitizeFn config option.
scrollbar.js
ScrollBarHelper handles hiding and restoring the browser scrollbar when Modal or Offcanvas opens. Calculates scrollbar width and applies compensating padding to prevent layout shift.
swipe.js
Touch event detection for Carousel. Detects horizontal swipe gestures and translates them into next/previous slide actions.
template-factory.js
Renders HTML templates for Tooltip and Popover. Handles content injection, sanitization, and class application.
component-functions.js
Exports enableDismissTrigger() — wires up [data-bs-dismiss="{component}"] buttons to call close() or hide() on the parent component. Used by Alert, Toast, Modal, and Offcanvas.
8.5 SCSS Architecture
Import Order
The main entry (scss/bootstrap.scss) imports partials in a specific, dependency-respecting order:
_functions.scss— Sass functions (must be first)_variables.scss— All variable definitions_variables-dark.scss— Dark mode overrides_maps.scss— Map finalization and merging_mixins.scss— All mixin imports_root.scss— CSS custom properties on:root_reboot.scss— Normalize + base styles- Component partials (type, images, containers, grid, tables, forms, buttons, etc.)
_helpers.scss— Helper classes_utilities.scss+utilities/_api.scss— Utility class generation (must be last)
Important
When creating custom builds, maintain this import order. Functions and variables must precede mixins, which must precede components. The utilities API must be imported last because it reads the finalized
$utilitiesmap to generate classes.
Mixins Directory (24 mixins)
| Mixin | Purpose |
|---|---|
_alert.scss |
Alert variant generator |
_backdrop.scss |
Backdrop styles |
_banner.scss |
Banner styles |
_border-radius.scss |
Border radius utilities |
_box-shadow.scss |
Box shadow utilities |
_breakpoints.scss |
Media query helpers (media-breakpoint-up, -down, -between, -only) |
_buttons.scss |
Button variant generator |
_caret.scss |
Dropdown caret styles |
_clearfix.scss |
Clearfix |
_color-mode.scss |
Color mode selector generation |
_color-scheme.scss |
Color scheme utilities |
_container.scss |
Container generator |
_deprecate.scss |
Deprecation warning helper |
_forms.scss |
Form variant generators |
_gradients.scss |
Gradient backgrounds |
_grid.scss |
Grid system (rows, columns) |
_image.scss |
Responsive image |
_list-group.scss |
List group variant generator |
_lists.scss |
List utilities |
_pagination.scss |
Pagination sizing |
_reset-text.scss |
Text reset |
_resize.scss |
Resize utility |
_table-variants.scss |
Table color variants |
_text-truncate.scss |
Text truncation |
_transition.scss |
Transition helpers |
_utilities.scss |
Utility generation engine |
_visually-hidden.scss |
Screen-reader-only |
Forms Directory (8 files)
_floating-labels.scss, _form-check.scss, _form-control.scss, _form-range.scss, _form-select.scss, _form-text.scss, _input-group.scss, _labels.scss, _validation.scss
Helpers Directory (12 files)
_clearfix.scss, _color-bg.scss, _colored-links.scss, _focus-ring.scss, _icon-link.scss, _position.scss, _ratio.scss, _stacks.scss, _stretched-link.scss, _text-truncation.scss, _visually-hidden.scss, _vr.scss
8.6 Event System Architecture
Bootstrap's event system is a complete abstraction over native DOM events:
User Action / JS Call
↓
EventHandler.trigger(element, 'show.bs.modal')
↓
Create native CustomEvent with:
- Namespaced type: 'show.bs.modal'
- cancelable: true (for show/hide)
- detail: { delegateTarget: element }
↓
element.dispatchEvent(event)
↓
Registered handlers execute
↓
If event.defaultPrevented → operation canceled
If not → proceed with show/hide logic
↓
EventHandler.trigger(element, 'shown.bs.modal')
8.7 Error Messages Reference
These are the error messages thrown by Bootstrap's JavaScript components:
| Error | Source | Cause |
|---|---|---|
TypeError: No method named "${config}" |
All plugins | Calling a nonexistent method via jQuery or data API |
TypeError: Bootstrap's dropdowns require Popper |
Dropdown | Popper.js not loaded when using standalone build |
Error: Please use show on visible elements |
Tooltip | Calling show() on a hidden or detached element |
TypeError: DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method |
Dropdown | Invalid reference element |
Error: You have to implement the static method "NAME" |
Config | Subclass missing required static get NAME() |
8.8 Testing Strategy
JavaScript Tests
- Framework: Jasmine + Karma
- Browser: Chrome (local), BrowserStack (cloud CI)
- Coverage target: 90%
- Test location:
js/tests/unit/*.spec.js - Visual tests:
js/tests/visual/*.html - Integration tests:
js/tests/integration/ - Run:
npm run js-test - Debug mode:
npm run js-debug(setsDEBUG=true)
SCSS Tests
- Framework: sass-true + Jasmine
- Test location:
scss/tests/ - Run:
npm run css-test(invokesjasmine --config=scss/tests/jasmine.js)
Linting
| Tool | Target | Command |
|---|---|---|
| ESLint (xo + import + unicorn) | JavaScript | npm run js-lint |
| Stylelint (twbs-bootstrap config) | SCSS | npm run css-lint |
| find-unused-sass-variables | SCSS | (part of css-lint) |
| Prettier | Docs site files | — |
| lockfile-lint | package-lock.json |
(part of lint) |
| vnu-jar | HTML | HTML validation |
8.9 Code Patterns and Conventions
- Data attribute prefix: All Bootstrap data attributes use the
data-bs-prefix - Event naming:
{event}.bs.{component}(e.g.,show.bs.modal) - Private methods: Prefixed with underscore (
_doSomething()) - Static interface: Every plugin exposes
jQueryInterface,getInstance,getOrCreateInstance - Config pattern:
Default+DefaultTypestatic getters on every configurable class - Disposal: Every component implements
dispose()for cleanup - jQuery noConflict: Each plugin supports
$.fn[name].noConflict()
9. Integration Points
9.1 jQuery Compatibility
Bootstrap auto-detects jQuery via window.jQuery at load time. When detected:
- Each plugin registers as
$.fn[name](e.g.,$('#myModal').modal('show')) - The
jQueryInterfacestatic method handles jQuery-style method calls $.fn[name].Constructorexposes the plugin class$.fn[name].noConflict()restores previous jQuery plugin binding
To disable jQuery detection, add data-bs-no-jquery to the <body> element.
9.2 Popper.js Integration
Three components depend on @popperjs/core ^2.11.8:
| Component | Popper Usage |
|---|---|
| Dropdown | Menu positioning relative to toggle |
| Tooltip | Tooltip positioning relative to trigger |
| Popover | Inherits Tooltip positioning |
Bundle build (bootstrap.bundle.js/.min.js) includes Popper — no separate import needed.
Standalone build (bootstrap.js/.esm.js) requires Popper loaded separately. If missing, Dropdown throws TypeError: Bootstrap's dropdowns require Popper.
Custom Popper configuration can be passed via the popperConfig option (object or function returning an object).
9.3 Bundler Integration
Webpack
// webpack.config.js
module.exports = {
resolve: {
// Use the ESM build for tree-shaking
mainFields: ['module', 'main']
}
};
// Import only what you need
import { Modal, Tooltip } from 'bootstrap';
For Sass integration, configure sass-loader to resolve Bootstrap's SCSS:
// webpack.config.js
{
loader: 'sass-loader',
options: {
sassOptions: {
// Bootstrap SCSS resolves via node_modules
}
}
}
Vite
// vite.config.js
import { resolve } from 'path';
export default {
css: {
preprocessorOptions: {
scss: {
// Custom variable overrides
additionalData: `@import "./src/custom-variables";`
}
}
}
};
// main.js — tree-shakeable imports
import { Dropdown, Modal } from 'bootstrap';
Parcel
Parcel resolves Bootstrap automatically from node_modules. Import SCSS directly:
// styles.scss
@import "bootstrap/scss/bootstrap";
Rollup
Bootstrap itself uses Rollup for its builds. For consuming projects:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
plugins: [resolve()]
};
9.4 Framework Integration
React
Bootstrap CSS can be imported directly. For JS components, use the imperative API rather than data attributes:
import { Modal } from 'bootstrap';
import { useEffect, useRef } from 'react';
function MyModal({ show, onHide }) {
const modalRef = useRef(null);
const bsModal = useRef(null);
useEffect(() => {
bsModal.current = new Modal(modalRef.current);
modalRef.current.addEventListener('hidden.bs.modal', onHide);
return () => bsModal.current.dispose();
}, []);
useEffect(() => {
if (show) bsModal.current.show();
else bsModal.current.hide();
}, [show]);
return <div ref={modalRef} className="modal fade">...</div>;
}
Tip
For React projects, consider libraries like
react-bootstraporreactstrapthat provide React-native component wrappers. If using Bootstrap's JS directly, always calldispose()in cleanup effects to prevent memory leaks.
Vue
Similar to React — import CSS globally and use the imperative JS API in lifecycle hooks:
import { Modal } from 'bootstrap';
export default {
mounted() {
this.bsModal = new Modal(this.$refs.modal);
this.$refs.modal.addEventListener('hidden.bs.modal', this.onHide);
},
beforeUnmount() {
this.bsModal.dispose();
}
};
9.5 Astro Docs Site Architecture
The Bootstrap documentation site is itself a substantial Astro application:
| Layer | Technology |
|---|---|
| Framework | Astro 5.18.1 (static site generation) |
| Content | MDX files in site/src/content/docs/ |
| Syntax highlighting | Prism |
| Markdown processing | rehype + remark plugins |
| Data | YAML files in site/data/ |
| Search | Algolia (app ID: AK7KMZKZHQ, index: bootstrap) |
| Analytics | Fathom (ITUSEYJG) |
The docs site uses two environment-only configuration values (NODE_ENV and DEPLOY_PRIME_URL) for build-time behavior — these are not user-facing configuration.
9.6 Known Open Issues
| Issue | Description |
|---|---|
| #41925 | Popover data-bs-content="true"/"false" auto-converted to boolean, causing TypeError |
| #42328 | Missing aria-pressed="false" at toggle button initialization |
| #40962 | dart-sass 1.80.0+ deprecation warnings |
| #39984 | Dark dropdowns/navbars don't receive dark variables with dark theme |
| #37807 | Grid system should support CSS Container Queries |
| #41192 | Variable for subtract .02px |
| #33761 | Alert JS closing event name doesn't fit naming conventions |
| #29378 | Expounding on "opt-in for performance reasons" |
Note
Issue #41925 is a practical trap: setting
data-bs-content="true"ordata-bs-content="false"on a Popover results in the string being coerced to a boolean by the Manipulator module, which then causes a TypeError. Use different string values or set content via JavaScript to avoid this.