Customization
|
This section documents Bootstrap 5.x as implemented by the official Bootstrap project. No specific patch version is pinned. Unlike the other reference sections on this site, no single reference book underpins it: the content was generated with the assistance of AI from general knowledge of Bootstrap, and should be verified against the current official documentation at getbootstrap.com/docs before relying on it in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Bootstrap is not meant to be used as a fixed, unmodifiable stylesheet — it is a Sass source distribution,
built specifically to be configured before compilation. This page covers the three main levers: overriding
Sass variables and maps to retheme colors, spacing, and fonts; compiling a trimmed build that only includes
what a project actually uses; and the layer of CSS custom properties Bootstrap 5 generates so some of that
theming can also be adjusted live in the browser. It assumes the underlying Sass mechanics — $variable
declarations, !default, and Sass maps — are already familiar; see Variables
and Compilation for those fundamentals rather than repeating them here.
Every Bootstrap variable is a configuration knob
Bootstrap’s own source declares its hundreds of variables with !default, exactly the pattern documented in
Variables: a value is assigned only if nothing has already defined that
variable. Bootstrap’s own Sass files load each other with @import, not @use — so a project overriding
Bootstrap must @import it too; @use "…" with (…) (the module-system override syntax covered in
Variables) has no effect on it, since with(…) only configures the module being
@use-d, not files that module itself later @import`s. `@import instead shares one global Sass scope, so a
plain variable assignment placed before Bootstrap’s own @import "bootstrap/scss/variables"; configures its
!default the same way any local variable would — no special syntax needed.
// _custom-bootstrap.scss
// 1. Functions first -- every Bootstrap partial that follows depends on it
@import "bootstrap/scss/functions";
// 2. Override individual variables -- these configure Bootstrap's own
// !default values because @import shares one global scope
$primary: #6f42c1;
$font-family-sans-serif: "Inter", system-ui, sans-serif;
$border-radius: 0.5rem;
// 3. Bootstrap's own variables -- skips every !default already set above
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
// 4. Override a whole map -- $theme-colors now exists, so it can be extended
$theme-colors: map-merge(
$theme-colors,
(
"brand": #6f42c1,
"accent": #ff6b6b
)
);
// 5. Everything else, including the rest of Bootstrap
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/bootstrap";
The ordering is not stylistic — it is required, and it runs in two passes for exactly the reason above: plain
variable overrides must come before @import "bootstrap/scss/variables" (so they pre-empt its !default`s),
but a map override that reads an existing map like `$theme-colors must come after that same import (so the
map exists to read from in the first place).
Theming via maps: colors, spacing, fonts
Most of Bootstrap’s theming surface is not individual variables but maps — $theme-colors, $spacers,
$font-sizes, $grid-breakpoints — for exactly the reason covered in
Lists & Maps: a map is one source of truth that a loop consumes to generate many
related outputs (utility classes, button variants, background/text color pairs) rather than each output being
hand-maintained separately.
@use "sass:map";
// Add a whole new theme color -- generates .btn-brand, .text-brand, .bg-brand,
// .border-brand, and more, automatically
$theme-colors: map.merge($theme-colors, ("brand": #6f42c1));
// Re-scale spacing from Bootstrap's default 0/0.25/0.5/1/1.5/3rem steps
$spacers: (
0: 0,
1: 0.25rem,
2: 0.5rem,
3: 1rem,
4: 2rem,
5: 4rem
);
// Swap the whole type scale
$font-family-base: "Source Sans Pro", sans-serif;
$font-size-base: 1rem;
$h1-font-size: $font-size-base * 2.5;
Adding one key to $theme-colors is enough to generate an entire family of component variants for that
color — buttons, alerts, badges, text/background utilities — because every one of those components' Sass
loops over $theme-colors rather than listing primary/secondary/success literally. This is the same
mechanism, applied to component styles rather than utility classes, that
The Utility API documents for $utilities specifically.
Compiling a trimmed custom build
Importing the single bootstrap/scss/bootstrap entry point pulls in every component’s styles, whether or not
a project uses them. For a project that only needs a handful of components, importing individual partials
instead produces a meaningfully smaller compiled stylesheet:
// 1. Required -- Bootstrap's own partials only support @import, not @use
@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";
// 2. Optional -- include only what's actually used
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/forms";
// 3. Utility API last, after any $utilities customization
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api";
Skipping @import "bootstrap/scss/card", …/modal, …/carousel, and every other unused component partial
means their CSS — and, for components with a JS behavior, the incentive to load their JS bundle too — never
ships. This is the Sass-level half of the story; the general compile pipeline (CLI vs. bundler, source maps,
--style=compressed) that this build ultimately runs through is documented in full in
Compilation.
Bootstrap’s use of CSS custom properties
Unlike a plain Sass variable, which is erased at compile time (see the comparison table in
Variables), Bootstrap 5 also defines many of its values as CSS custom properties
on :root, prefixed --bs-:
:root,
[data-bs-theme="light"] {
--bs-primary: #0d6efd;
--bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--bs-border-radius: 0.375rem;
--bs-gutter-x: 1.5rem;
}
This is why a color mode can be switched at runtime — no recompile — via a single data-bs-theme attribute:
Bootstrap 5.3 ships a [data-bs-theme="dark"] block that redefines the same --bs-* custom properties with
dark-mode values, and every component that reads var(--bs-body-bg) rather than a hard-coded color picks up
the change instantly:
<html data-bs-theme="dark">
<!-- every Bootstrap component on the page now uses the dark-mode custom property values -->
</html>
A component’s own compiled CSS typically reads its custom property with a Sass-computed fallback, e.g.
border-radius: var(--bs-border-radius, 0.375rem): the Sass variable still decides the value baked into the
stylesheet at build time, but the custom property built from it can still be overridden live afterward,
without touching the Sass source at all:
.card {
--bs-card-border-radius: 1rem; /* override just this one component's radius, on this one card */
}
This two-layer model — a Sass variable decides the compiled default, a same-named CSS custom property lets that default be overridden per-element or per-theme at runtime — is exactly the pattern described generically in Variables's "Sass variables vs. CSS custom properties" section; Bootstrap 5 is simply the largest real-world example of applying it consistently across an entire component library.
The override-and-compile pipeline
$primary, $font-family-base, ..."] MAPS["Map overrides
$theme-colors, $spacers via map.merge"] end IMPORT["@import 'bootstrap'
(full or trimmed partials)"] COMPILER["Dart Sass compiler"] CSS["Compiled CSS
component classes + :root custom properties"] RUNTIME["Browser
data-bs-theme switch, per-element --bs-* overrides"] VARS --> IMPORT MAPS --> IMPORT IMPORT --> COMPILER COMPILER --> CSS CSS --> RUNTIME classDef core fill:#3f51b5,stroke:#1a237e,color:#fff class COMPILER core
Everything left of the compiler is resolved once, at build time, exactly like the generic Sass pipeline in
Compilation. Everything right of it — the data-bs-theme switch, an
element-scoped --bs-card-border-radius override — happens live in the browser, with no rebuild, because it
targets the CSS custom properties the compiled stylesheet already shipped.