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

flowchart LR subgraph config["Project Sass configuration"] VARS["Variable overrides
$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.