How to Customize Bootstrap 5 Colors
The fastest way to recolor Bootstrap 5 is to override $primary and the $theme-colors map before you import Bootstrap, or do it visually in the builder and export the result. Either way you get standard, framework-native output. This guide covers both routes, how Bootstrap 5.3’s color system actually works (including the new subtle and emphasis variants), how to add your own brand color, and the mistakes that quietly stop a color change from taking effect. Color is one piece of the bigger picture, so for the full workflow see the complete guide to customizing Bootstrap 5.
The quick way: recolor in the browser
If you just want a new palette without touching a terminal, open the visual builder, search for $primary (or open the “Color system” section), and set your brand color. Every component that derives from it (buttons, links, alerts, badges, focus rings, pagination) updates in the live preview at once. Crucially, the builder recomputes the derived values too: hover and active shades, the subtle backgrounds, the emphasis text, and the contrast color for button labels. So you see the real, accessible result rather than a guess. When it looks right, export a clean _variables.scss or the compiled bootstrap.css. Skip to “Use your exported file” to wire it in.
How Bootstrap’s color system works
Bootstrap builds its components from three layers of color:
- A base palette:
$blue,$indigo,$red,$green,$gray-500, and so on. These are raw colors with no meaning yet. - Theme colors that give those values a role:
$primary,$secondary,$success,$info,$warning,$danger,$light,$dark. By default$primaryis$blue,$dangeris$red, and so on. - The
$theme-colorsmap that ties them together. Bootstrap loops over this map to generate utilities like.bg-primaryand.text-successand component variants like.btn-dangerand.alert-warning.
Change a theme color and everything built on it follows. This is why $primary is the single highest-impact variable in the framework: it restyles buttons, links, pagination, list groups, nav pills, progress bars, spinners, and form focus states in one move.
The 5.3 addition: subtle and emphasis variants
Bootstrap 5.3 expanded each theme color into a small family, exposed as CSS variables, to support color modes:
| Variable | Used for |
|---|---|
--bs-primary |
the solid color (buttons, links) |
--bs-primary-rgb |
rgba() usage, like translucent backgrounds |
--bs-primary-bg-subtle |
tinted backgrounds (alerts, list groups) |
--bs-primary-border-subtle |
matching subtle borders |
--bs-primary-text-emphasis |
readable text on a subtle background |
When you set $primary in Sass, Bootstrap derives this whole family for both light and dark modes, which is why a single override looks consistent everywhere.
Override colors with Sass
Bootstrap variables carry the !default flag, so your value wins only if you declare it before you import Bootstrap. Load Bootstrap’s functions first (your overrides may use them), then your overrides, then the rest:
// 1. Functions first (the variables below depend on them)
@import "bootstrap/scss/functions";
// 2. Your overrides
$primary: #2f55ff;
$success: #18a957;
$danger: #e5484d;
$body-color: #0b1220;
$body-bg: #ffffff;
// 3. The rest of Bootstrap
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap";
That is the whole repaint. If a color change is being ignored, the order above is almost always the reason; the full mechanism and the three variable tiers are in Bootstrap Sass variables explained.
Set the page background and text
Two variables define the canvas the rest of your theme sits on: $body-bg (the page background) and $body-color (the default text color). Bootstrap 5.3 also adds $body-secondary-color and $body-tertiary-bg for muted text and subtle surfaces. Setting these first makes every component read correctly against your background.
Add your own theme color
Need a brand color beyond the built-in eight? Merge it into $theme-colors (merge, do not replace, or you lose the defaults), and Bootstrap generates the matching utilities and component variants automatically:
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
$theme-colors: map-merge($theme-colors, (
"brand": #6b4eff,
));
@import "bootstrap";
You now get .bg-brand, .text-brand, .btn-brand, .alert-brand, and the rest, exactly as if the color shipped with the framework.
Watch contrast on light brand colors
Bootstrap chooses each button’s text color automatically with its color-contrast() function, comparing the background against $min-contrast-ratio (4.5 by default). If you pick a light brand color, Bootstrap will correctly switch the label to dark text, but the button can still look washed out. The fix is to choose a slightly darker brand shade for solid buttons, or set the contrast threshold deliberately. The builder shows the computed label color live, so you catch this before shipping.
Tweak colors at runtime with CSS variables
For quick, scoped changes with no recompile, override the CSS custom properties directly:
.promo {
--bs-primary: #e5484d;
--bs-primary-rgb: 229, 72, 77; /* keep in sync for rgba() usage */
--bs-body-bg: #fff5f5;
}
Use Sass variables to define your theme once (they recompute hover states, subtle backgrounds, and contrast text); reach for CSS variables for local, runtime overrides like a single highlighted section. The same CSS-variable system powers Bootstrap 5.3 dark mode.
Common mistakes
- Overriding after the import. The value is ignored because of
!default. Move it above@import "bootstrap/scss/variables". - Replacing
$theme-colorsinstead of merging. A bare assignment wipes the built-in colors; usemap-merge. - Expecting
.btn-brandwithout merging the map. Setting a standalone$brandvariable does not generate utilities; it has to be in$theme-colors. - A light brand color with unreadable buttons. Pick a darker shade for solid variants or adjust
$min-contrast-ratio.
Use your exported file
However you land on a palette, drop the exported _variables.scss into the override slot above (after functions, before the rest of Bootstrap) and recompile. If you exported the compiled CSS instead, just link bootstrap.min.css and you are done, no build step required. The full export workflow is in how to export a Bootstrap theme.
Next steps
Color is the highest-impact change, but it is only the start. Continue with fonts and typography, dark mode, and the underlying Sass variable system. The quickest path through all of it is the visual builder: change a value, watch a full UI kit react, and export real Bootstrap Sass or CSS.
FAQ
How do I change the primary color in Bootstrap 5?
Override $primary before importing Bootstrap: @import "bootstrap/scss/functions"; $primary: #2f55ff; @import "bootstrap";. Bootstrap recomputes buttons, links, focus rings, and the rest from it. The no-setup route is the builder, which edits $primary and exports the result.
How do I add a custom color to Bootstrap?
Merge it into the $theme-colors map after the variables import: $theme-colors: map-merge($theme-colors, ("brand": #6b4eff));. Bootstrap then generates .btn-brand, .bg-brand, .text-brand, and the other utilities for it.
Why isn’t my Bootstrap color change applying?
Almost always because the override runs after Bootstrap’s variables import. Bootstrap variables use !default, so they only accept your value if it is set earlier. Move every color override above @import "bootstrap/scss/variables".
What is the difference between $primary and --bs-primary?
$primary is a Sass variable resolved at compile time; it decides what CSS is generated. --bs-primary is a CSS custom property in the compiled output that you can override live in the browser, per element or per theme, without recompiling.
Try it in the builder
Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.
Open the Builder