bootstrap
Bootstrap 5 is a browser UI framework that packages a responsive grid, normalized base styles, utility classes, form styling, and ready-made components such as navbars, modals, dropdowns, accordions, toasts, and offcanvas panels. You can use compiled CSS alone, add data-attribute-driven JavaScript plugins, or compile selected Sass sources with your own variables. Version 5 uses plain JavaScript rather than jQuery, supports right-to-left builds, and includes CSS-variable color modes.
Bootstrap remains an excellent speed-to-consistency choice for server-rendered sites, admin tools, and teams that accept its visual grammar. Skip it for a bespoke product design or when your framework already supplies accessible components and layout primitives.
Use it if
- You need a conventional, responsive admin panel or internal tool quickly and custom visual identity is secondary
- Your team prefers documented HTML class patterns over building and maintaining its own layout, spacing, form, and component primitives
- You need one framework that works with server-rendered HTML and does not require React, Vue, or another component runtime
- You want a large ecosystem of templates, examples, themes, community answers, and developers who already recognize the conventions
- Your product needs a distinctive design system: changing Bootstrap's recognizable component proportions and state styles often becomes a long Sass-variable and override project
- You already use React, Vue, or another component framework with an accessible component kit; Bootstrap's JavaScript plugins are imperative DOM objects, not official framework components
- You only need layout and a few utilities: importing the complete CSS and roughly 16.0 KB gzipped JavaScript ships many component rules and behaviors you will never call
- You expect accessibility from classes alone: the documentation still makes authors supply correct labels, headings, keyboard context, color contrast, and ARIA relationships for their actual content
- You want a modern Sass module-only pipeline with no warnings: Bootstrap 5.3's source customization still centers on Sass @import ordering, while Dart Sass is retiring that mechanism
Setup reality
The fastest setup is one stylesheet link plus bootstrap.bundle.min.js; the bundle includes Popper, which dropdowns, popovers, and tooltips need. With npm, import bootstrap/dist/css/bootstrap.min.css and either bootstrap/dist/js/bootstrap.bundle.min.js or individual plugin modules. The package declares @popperjs/core ^2.11.8 as a peer dependency. Package managers normally install it, but strict or manual setups must account for it, and importing the non-bundle build without Popper breaks positioned overlays. JavaScript is optional for the grid, utilities, forms, alerts styled as static markup, and many cards. It is required for collapse, modal, dropdown, offcanvas, tooltip, popover, toast, and programmatic component state. Tooltips and popovers are opt-in: data attributes do nothing until JavaScript initializes them. Sass customization is order-sensitive. Import functions first, override variables before variables and maps are consumed, then import the remaining sources; importing the compiled CSS and trying to replace Sass variables afterward cannot work. Bootstrap's responsive breakpoints and spacing utilities encode framework decisions that spread through markup, so replacing the framework later means editing templates, not only swapping a stylesheet. Color modes use data-bs-theme on html or a nested element, but your custom colors and third-party widgets need their own dark-mode treatment. The distribution includes separate RTL CSS rather than runtime direction conversion. Content Security Policy generally works because plugins do not require eval, but CDN files should use the documented integrity and crossorigin attributes. In app frameworks, dispose plugin instances when DOM nodes are removed to avoid stale listeners and references.
Patterns
Load compiled Bootstrap from a CDNcdn-starter
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<main class="container py-4">
<h1>Hello</h1>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>The bundle build includes Popper. For production, copy the integrity and crossorigin values from Bootstrap's current quick-start documentation.
Import the compiled CSS and JavaScript bundlenpm-global-import
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';This loads every component. CSS-only pages can omit the JavaScript import entirely.
Import and create one JavaScript pluginimport-one-plugin
import 'bootstrap/dist/css/bootstrap.min.css';
import Modal from 'bootstrap/js/dist/modal';
const element = document.querySelector('#confirm-modal');
const modal = Modal.getOrCreateInstance(element, { keyboard: true });
modal.show();Individual imports reduce JavaScript, but dropdown, tooltip, and popover still require @popperjs/core.
Build a responsive card gridresponsive-grid
<div class="container">
<div class="row g-3">
<div class="col-12 col-md-6 col-xl-4"><article class="card p-3">A</article></div>
<div class="col-12 col-md-6 col-xl-4"><article class="card p-3">B</article></div>
<div class="col-12 col-md-6 col-xl-4"><article class="card p-3">C</article></div>
</div>
</div>Bootstrap is mobile-first: col-12 applies first, then md and xl override it at their minimum widths.
Create a collapsing navigation barresponsive-navbar
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="/">Acme</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#main-nav" aria-controls="main-nav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="main-nav">
<a class="nav-link" href="/docs">Docs</a>
</div>
</div>
</nav>The collapse behavior needs Bootstrap JavaScript. Keep data-bs-target, id, and aria-controls synchronized.
Open a modal from data attributesopen-modal
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#confirm-modal">Delete</button>
<div class="modal fade" id="confirm-modal" tabindex="-1" aria-labelledby="confirm-title" aria-hidden="true">
<div class="modal-dialog"><div class="modal-content">
<div class="modal-header"><h2 class="modal-title fs-5" id="confirm-title">Confirm deletion</h2></div>
<div class="modal-body">This cannot be undone.</div>
</div></div>
</div>Bootstrap manages focus while open, but the author must provide a meaningful label and an action that closes or completes the dialog.
Initialize opt-in tooltipsenable-tooltips
import Tooltip from 'bootstrap/js/dist/tooltip';
const tooltips = [...document.querySelectorAll('[data-bs-toggle="tooltip"]')]
.map((element) => new Tooltip(element));Tooltip data attributes do nothing until initialized, and this plugin requires Popper. Do not hide essential information only in a hover tooltip.
Create and show a toastshow-toast
import Toast from 'bootstrap/js/dist/toast';
const element = document.querySelector('#saved-toast');
const toast = Toast.getOrCreateInstance(element, { delay: 5000 });
toast.show();
element.addEventListener('hidden.bs.toast', () => toast.dispose(), { once: true });Add an appropriate live-region role in the HTML. dispose removes Bootstrap's stored instance and listeners after the toast is done.
Switch between light and dark color modestoggle-color-mode
const root = document.documentElement;
function setTheme(theme) {
root.setAttribute('data-bs-theme', theme);
localStorage.setItem('theme', theme);
}
setTheme(localStorage.getItem('theme') || 'light');data-bs-theme changes Bootstrap color variables. Custom CSS and third-party widgets need their own compatible variables or selectors.
Apply Bootstrap validation styles after submitvalidate-form
const form = document.querySelector('.needs-validation');
form.addEventListener('submit', (event) => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
});The styles reflect native constraint validation. Server errors still need explicit messages, invalid classes, and accessible associations.
Override Sass variables before compiling Bootstrapcustomize-sass
// styles.scss
@import "bootstrap/scss/functions";
$primary: #5b21b6;
$border-radius: .25rem;
$enable-shadows: true;
@import "bootstrap/scss/bootstrap";Variable order matters, and Bootstrap 5.3 still uses Sass @import internally. Current Dart Sass may print deprecation warnings.
Dispose a plugin before removing its elementdispose-on-removal
import Offcanvas from 'bootstrap/js/dist/offcanvas';
const element = document.querySelector('#filters');
const panel = Offcanvas.getOrCreateInstance(element);
panel.hide();
element.addEventListener('hidden.bs.offcanvas', () => {
panel.dispose();
element.remove();
}, { once: true });Framework-rendered DOM can disappear without Bootstrap knowing. Dispose instances before permanent removal to release listeners and references.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| bulma | npm | You want a CSS-only component framework and prefer to supply all interactive behavior yourself |
| tailwindcss | npm | You want low-level utilities and a custom design language instead of predesigned components |
| @picocss/pico | npm | You want attractive semantic HTML with far fewer classes and only a small component surface |