Key Takeaways
- Overriding Bootstrap CSS directly instead of using the correct customisation layer breaks future upgrade paths.
- Misusing the grid — especially nesting rows without proper column wrappers — is the leading cause of unexpected layout shifts.
- Bootstrap 5’s JavaScript components require correct data attribute naming (
data-bs-), not Bootstrap 4’sdata-syntax. - Skipping
position-relativeon a parent when usingposition-absolutechildren is a layout trap that catches even experienced developers. - Ignoring utility class specificity leads to styles that silently fail — understanding the cascade saves hours of debugging.
- Accessibility attributes on interactive components are not optional; missing them causes WCAG failures and broken keyboard navigation.
Mistake 1: Overriding Bootstrap’s Source CSS Directly
The most damaging long-term mistake is editing bootstrap.min.css or the compiled Bootstrap stylesheet to change colours, spacing, or typography. It works once, but every future Bootstrap upgrade wipes those changes. The correct approach is to override via a custom stylesheet loaded after Bootstrap, or — better — to use Bootstrap’s own Sass variable layer before compilation.
For Sass-based projects, set your overrides before importing Bootstrap:
// custom.scss — load BEFORE Bootstrap imports
$primary: #7c3aed;
$border-radius: 0.5rem;
@import "bootstrap/scss/bootstrap";
If you are working with a premium template like the Canvas HTML Template, CSS custom properties (e.g. --cnvs-themecolor) give you a runtime theming layer that requires zero recompilation and survives upgrades cleanly. The trade-offs between these two approaches are worth understanding in depth — see SCSS vs CSS Variables for Theming Bootstrap 5 for a full comparison.

Mistake 2: Nesting Grid Rows Without Column Wrappers
Bootstrap 5’s grid requires that every .row contains .col-* children, and every nested .row lives inside a column. A common mistake is placing a .row directly inside another .row, which produces unexpected negative margins and gutters that are painful to trace.
Content
Content
Bootstrap 5 introduced .row-cols- utilities and CSS Grid integration (.row.row--cols- with --bs-columns) that reduce the need for deep nesting in the first place. Reach for those before adding another layer of rows.
Mistake 3: Using Bootstrap 4 Data Attributes in Bootstrap 5
This is the single most common migration error. Bootstrap 5 renamed all JavaScript data attributes from data-toggle, data-target, and data-dismiss to their data-bs-* equivalents. If your modals, dropdowns, or toasts silently do nothing, this is the first place to look.
Run a project-wide search for data-toggle and data-dismiss whenever you migrate from Bootstrap 4. There is no deprecation warning in the browser — the attribute simply does nothing.

Mistake 4: Forgetting position-relative on the Parent Element
Using Bootstrap’s position-absolute utility on a child element without setting position-relative (or any non-static position) on its parent causes the child to escape the intended container and anchor to the nearest positioned ancestor — often the viewport itself. This shows up most often with overlay badges, icon anchors, and custom dropdown indicators.
New
Card content
New
Card content
Mistake 5: Fighting Utility Class Specificity
Bootstrap 5 utility classes each have a specificity of one class (0,1,0). When you write a custom component rule with the same or higher specificity, the utility silently loses — or vice versa, your component styles get steamrolled by a utility you added later. The most reliable fix is to use Bootstrap 5.3+’s !important-flagged utilities (enabled by $enable-important-utilities: true in Sass, which is the default) and to keep your component CSS in a separate layer so the cascade is predictable.
// Wrap your custom component rules in a CSS @layer
// so Bootstrap utilities always win when you need them to
@layer components {
.site-header {
background-color: #fff;
padding: 1rem 1.5rem;
}
}
CSS @layer is supported in all modern browsers as of 2023 and is the cleanest long-term solution for specificity management alongside utility-first frameworks.
Mistake 6: Omitting Required ARIA and Accessibility Attributes
Bootstrap 5’s interactive components — modals, dropdowns, accordions, offcanvas panels — require specific ARIA attributes to function correctly for keyboard and screen reader users. The official docs show these attributes, but copy-paste shortcuts often strip them out.
Missing these attributes causes WCAG 2.1 Level AA failures. Browser DevTools’ Accessibility panel (available in Chrome and Firefox) will flag them before any audit tool does.
Mistake 7: Implementing Dark Mode with Only a CSS Class Toggle
A common shortcut is toggling a .dark class on <body> and writing a wall of overrides. Bootstrap 5.3 introduced a native data-bs-theme="dark" attribute system that hooks into the framework’s own CSS custom properties, meaning all Bootstrap components adapt automatically without override duplication. Applying this attribute to a scoped section rather than the root element also lets you run mixed-theme layouts.
For production implementations — including how to persist user preference via localStorage and respect prefers-color-scheme — the post How to Add Dark Mode to a Bootstrap 5 HTML Template the Right Way covers the full pattern.
Mistake 8: Loading the Full Bootstrap Bundle When You Only Need Part of It
Including bootstrap.bundle.min.js (which bundles Popper.js) on a page that uses no dropdowns, tooltips, or popovers adds approximately 22 KB of gzip-compressed JavaScript for no reason. For content-heavy pages with no interactive components, load only bootstrap.min.js (no Popper). For highly selective projects, import only the specific modules you need via ES module syntax:
// Only import what this page actually uses
import { Modal, Toast } from 'bootstrap';
const myModal = new Modal(document.getElementById('myModal'));
Similarly, if you are using Bootstrap’s Sass source, enabling $enable-grid-only: false and commenting out unused component imports in your Sass entry point can reduce output CSS by 30–50% on minimal projects. Unnecessary payload has a direct impact on Core Web Vitals — for a detailed look at performance optimisation for Bootstrap projects, see How to Optimise Bootstrap 5 Images for Core Web Vitals.
Frequently Asked Questions
The most likely cause is using Bootstrap 4 data attribute syntax. Check that your trigger button uses data-bs-toggle="modal" and data-bs-target="#yourModalId". Also verify that bootstrap.bundle.min.js (or a standalone bootstrap.min.js alongside Popper) is loaded before your custom scripts, and that the modal element has a matching id.
If you compile Sass, define your overrides before the Bootstrap @import statement. If you use the pre-compiled CSS, add a custom stylesheet loaded after Bootstrap and use CSS custom properties where available. Avoid editing Bootstrap source files directly.
Ensure your custom component styles have equal or lower specificity than the utility classes, or wrap your component rules in a CSS @layer declaration so Bootstrap utilities (which are flagged !important by default) take precedence when applied. Alternatively, increase specificity on your rules deliberately using a parent class or :is() selector.
bootstrap.bundle.js includes Popper.js, which is required for dropdowns, tooltips, and popovers. bootstrap.js does not include Popper — use it when you are loading Popper separately or when your project does not use those components. Loading the bundle unnecessarily adds around 22 KB (gzipped) of JavaScript.
For most projects, yes. Setting data-bs-theme="dark" on the <html> element activates Bootstrap’s built-in dark palette across all components automatically. You still need a small JavaScript snippet to read and persist the user’s preference via localStorage and to respond to the prefers-color-scheme media query on first load. The Bootstrap 5 native approach is significantly less maintenance than a manual class-toggle override system.
Looking for a production-ready Bootstrap 5 HTML template? Browse Canvas Template demos and find the perfect starting point for your next project.
If you’re building with the Canvas HTML Template and want to ship production-ready Bootstrap 5 layouts faster, try Canvas Builder free — the visual builder that exports clean Canvas-ready markup in minutes.
Skip the setup — build it free
Spin up a complete Bootstrap 5 site, blog included, with Canvas Builder. No coding, no cost.
Canvas Team
Tutorials and tips for building beautiful Bootstrap 5 websites with the Canvas HTML Template and Canvas Builder.
More from the Canvas Blog