Sleek, intuitive, and powerful front-end framework for faster and easier web development.
Explore Bootstrap docs »
Report bug
·
Request feature
·
Blog
This is a fork of Bootstrap 5.3.8 that makes all component colors fully CSS-var-driven. Override a few base tokens on any element and all derived colors (contrast, emphasis, link, border, etc.) auto-update via modern CSS.
Set base colors on any element. Everything else auto-derives:
.color-schema-ocean {
--bs-primary: #0077b6;
--bs-primary-rgb: 0, 119, 182;
--bs-body-bg: #f8f9fa;
--bs-body-color: #1d3557;
}Auto-derived tokens (no manual override needed):
| Token | Derived from | Method |
|---|---|---|
--bs-on-* (contrast text) |
--bs-{color} |
oklch lightness flip |
--bs-emphasis-color |
--bs-body-bg |
oklch lightness flip |
--bs-link-color |
--bs-primary |
var() |
--bs-link-hover-color |
--bs-primary |
color-mix() shade 20% |
--bs-secondary-color |
--bs-body-color |
color-mix() 75% opacity |
--bs-tertiary-color |
--bs-body-color |
color-mix() 50% opacity |
--bs-secondary-bg |
--bs-body-bg + --bs-body-color |
color-mix() 10% tint |
--bs-tertiary-bg |
--bs-body-bg + --bs-body-color |
color-mix() 3% tint |
--bs-border-color |
--bs-body-bg + --bs-body-color |
color-mix() 15% |
--bs-border-color-translucent |
--bs-body-color |
color-mix() 17.5% opacity |
--bs-focus-ring-color |
--bs-primary |
color-mix() 25% opacity |
Modals and offcanvas are standalone overlays — they don't automatically inherit a section's theme. To theme them, set the base tokens directly:
<div class="modal" id="myModal"
style="--bs-primary: #0077b6; --bs-primary-rgb: 0,119,182; --bs-body-bg: #f8f9fa; --bs-body-color: #1d3557;">
...
</div>Tooltips and popovers are handled automatically — css-var-scoping.js copies all --bs-* custom properties from the trigger element to the tip.
CSS custom properties with var() references resolve where the property is defined, not where it's inherited. This creates a fundamental problem for section-level theming:
/* Vanilla Bootstrap approach — BROKEN for sections */
:root {
--bs-primary: #0d6efd;
--bs-link-color: var(--bs-primary); /* resolves to #0d6efd at :root */
--bs-focus-ring-color: color-mix(in srgb, var(--bs-primary) 25%, transparent);
}
.color-schema-ocean {
--bs-primary: #0077b6;
/* --bs-link-color is STILL #0d6efd — inherited from :root where it was computed */
}The :root element computed --bs-link-color using its own --bs-primary value (#0d6efd). Children inherit the computed result, not the var() expression. Overriding --bs-primary on a child has no effect on --bs-link-color.
The fix: define derived tokens on *, so every element gets its own computation:
:root {
--bs-primary: #0d6efd;
--bs-link-color: #0d6efd; /* static fallback, wins on :root (specificity 0,1,0) */
}
* {
--bs-link-color: var(--bs-primary); /* re-resolves per element (specificity 0,0,0) */
}
.color-schema-ocean {
--bs-primary: #0077b6;
/* Now --bs-link-color resolves to #0077b6 inside this section */
}Why this is safe:
*has specificity(0,0,0)— any class, attribute, or id selector overrides it:rootretains static fallbacks at specificity(0,1,0), winning on the<html>element- Dark mode (
.dark-mode/[data-bs-theme=dark]) has specificity(0,1,0), always overriding* - CSS engines optimize custom property resolution —
*does not cause measurable performance overhead - The pattern is used by design systems like Open Props and Material Web Components
What * does NOT do:
- It does not apply layout, box model, or visual properties to every element
- It only sets custom properties (which are inherited by default anyway)
- It does not interfere with component-level CSS variable overrides
The conventional advice is to define derived calculations at component level (e.g. .btn { --hover-bg: color-mix(...) }). This works when you have a handful of components, but breaks down when the derived tokens are cross-cutting — used by buttons, links, alerts, tables, focus rings, borders, and text utilities simultaneously. You'd need to repeat the same color-mix() expressions in dozens of selectors and keep them in sync.
The * selector is the only approach that lets consumers override a single base token (--bs-primary) and have all derived tokens update everywhere, without repeating calculations per component.
If you don't need section-level theming, disable the * block:
$enable-derived-vars: false;
@import "bootstrap";Bootstrap then behaves like vanilla — all tokens are static on :root. If you still want per-section theming without *, you must set all derived tokens yourself on each section class:
.color-schema-ocean {
--bs-primary: #0077b6;
--bs-primary-rgb: 0, 119, 182;
/* All derived tokens — you must repeat these per section */
--bs-on-primary: #fff;
--bs-link-color: #0077b6;
--bs-link-hover-color: color-mix(in srgb, #0077b6, black 20%);
--bs-focus-ring-color: color-mix(in srgb, #0077b6 25%, transparent);
--bs-border-color: color-mix(in srgb, var(--bs-body-bg), var(--bs-body-color) 15%);
--bs-border-color-translucent: color-mix(in srgb, var(--bs-body-color) 17.5%, transparent);
--bs-secondary-color: color-mix(in srgb, var(--bs-body-color) 75%, transparent);
--bs-secondary-bg: color-mix(in srgb, var(--bs-body-bg), var(--bs-body-color) 10%);
--bs-tertiary-color: color-mix(in srgb, var(--bs-body-color) 50%, transparent);
--bs-tertiary-bg: color-mix(in srgb, var(--bs-body-bg), var(--bs-body-color) 3%);
--bs-emphasis-color: oklch(from var(--bs-body-bg) calc((0.6 - l) * 999) 0 h);
}Further reading:
- How Custom Property Values are Computed — Stephanie Eckles explains why
:rootcomputed values are "inheritable, but immutable" and won't update when descendants override input variables - Breaking CSS Custom Properties out of :root — CSS-Tricks on why not everything belongs on
:rootand the case for scoped custom properties - CSS Custom Properties Beyond the :root — Matthias Ott argues there is "no real reason" for the
:rootconvention and demonstrates component-scoped patterns - A Strategy Guide To CSS Custom Properties — Smashing Magazine deep dive on local vs global scoping strategies
- CSS Custom Properties In The Cascade — how custom properties participate in the cascade and why that matters for theming
--bs-on-* uses the oklch lightness trick: oklch(from var(--bs-primary) calc((0.6 - l) * 999) 0 h) — dark colors get white text, light colors get black text. Wrapped in @supports (color: oklch(from red l c h)) so older browsers fall back to the static values on :root.
Tier 1 (color-mix(), unconditional): Chrome 111+, Firefox 113+, Safari 16.2+. Covers link, hover, secondary/tertiary, border, and focus ring tokens.
Tier 2 (oklch relative color syntax, @supports gated): Chrome 131+, Firefox 133+, Safari 18+. Covers --bs-on-* contrast tokens and --bs-emphasis-color. Without Tier 2, these tokens use static :root fallbacks — section overrides won't auto-derive contrast text, but all other theming works.
Bootstrap appends tooltips/popovers to <body>, outside any themed section. css-var-scoping.js handles this automatically: when a tip is inserted, it compares the trigger's computed --bs-* properties with :root and copies any differences to the tip element. No extra attributes or markup needed.
Bootstrap uses SVG data URIs for component icons (checkmarks, chevrons, togglers). SVGs can't reference CSS custom properties, so icon colors are normally hardcoded at compile time.
This fork uses CSS mask-image to decouple icon shape from color — the SVG becomes a shape mask and the visible color comes from background, which CAN use CSS vars:
| Component | Approach | Icon color follows |
|---|---|---|
| Close button | mask |
--bs-emphasis-color |
| Accordion chevron | mask |
--bs-accordion-btn-color / --bs-accordion-active-color |
| Navbar toggler | mask |
--bs-navbar-color |
Dark-mode SVG overrides for these components are eliminated — the color adapts automatically.
Not convertible (element shares background-color with the icon):
| Component | Reason | Mitigation |
|---|---|---|
| Form select chevron | <select> has its own bg-color |
Dark-mode override via color-mode() |
| Form switch circles | <input> track IS the bg-color |
Dark-mode override via color-mode() |
| Checkbox/radio/indeterminate | White on primary bg — universally correct | No change needed |
| Carousel arrows | White on dark overlay — universally correct | No change needed |
| Validation icons | Colors track $form-validation-states map |
Already themeable via Sass |
Our default branch is for development of our Bootstrap 5 release. Head to the v4-dev branch to view the readme, documentation, and source code for Bootstrap 4.
- Quick start
- Status
- What’s included
- Bugs and feature requests
- Documentation
- Contributing
- Community
- Versioning
- Creators
- Thanks
- Copyright and license
Several quick start options are available:
- Download the latest release
- Clone the repo:
git clone https://github.com/twbs/bootstrap.git - Install with npm:
npm install bootstrap@v5.3.8 - Install with yarn:
yarn add bootstrap@v5.3.8 - Install with Bun:
bun add bootstrap@v5.3.8 - Install with Composer:
composer require twbs/bootstrap:5.3.8 - Install with NuGet: CSS:
Install-Package bootstrapSass:Install-Package bootstrap.sass
Read the Getting started page for information on the framework contents, templates, examples, and more.
Within the download you’ll find the following directories and files, logically grouping common assets and providing both compiled and minified variations.
Download contents
bootstrap/
├── css/
│ ├── bootstrap-grid.css
│ ├── bootstrap-grid.css.map
│ ├── bootstrap-grid.min.css
│ ├── bootstrap-grid.min.css.map
│ ├── bootstrap-grid.rtl.css
│ ├── bootstrap-grid.rtl.css.map
│ ├── bootstrap-grid.rtl.min.css
│ ├── bootstrap-grid.rtl.min.css.map
│ ├── bootstrap-reboot.css
│ ├── bootstrap-reboot.css.map
│ ├── bootstrap-reboot.min.css
│ ├── bootstrap-reboot.min.css.map
│ ├── bootstrap-reboot.rtl.css
│ ├── bootstrap-reboot.rtl.css.map
│ ├── bootstrap-reboot.rtl.min.css
│ ├── bootstrap-reboot.rtl.min.css.map
│ ├── bootstrap-utilities.css
│ ├── bootstrap-utilities.css.map
│ ├── bootstrap-utilities.min.css
│ ├── bootstrap-utilities.min.css.map
│ ├── bootstrap-utilities.rtl.css
│ ├── bootstrap-utilities.rtl.css.map
│ ├── bootstrap-utilities.rtl.min.css
│ ├── bootstrap-utilities.rtl.min.css.map
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap.min.css.map
│ ├── bootstrap.rtl.css
│ ├── bootstrap.rtl.css.map
│ ├── bootstrap.rtl.min.css
│ └── bootstrap.rtl.min.css.map
└── js/
├── bootstrap.bundle.js
├── bootstrap.bundle.js.map
├── bootstrap.bundle.min.js
├── bootstrap.bundle.min.js.map
├── bootstrap.esm.js
├── bootstrap.esm.js.map
├── bootstrap.esm.min.js
├── bootstrap.esm.min.js.map
├── bootstrap.js
├── bootstrap.js.map
├── bootstrap.min.js
└── bootstrap.min.js.map
We provide compiled CSS and JS (bootstrap.*), as well as compiled and minified CSS and JS (bootstrap.min.*). Source maps (bootstrap.*.map) are available for use with certain browsers’ developer tools. Bundled JS files (bootstrap.bundle.js and minified bootstrap.bundle.min.js) include Popper.
Have a bug or a feature request? Please first read the issue guidelines and search for existing and closed issues. If your problem or idea is not addressed yet, please open a new issue.
Bootstrap’s documentation, included in this repo in the root directory, is built with Astro and publicly hosted on GitHub Pages at https://getbootstrap.com/. The docs may also be run locally.
Documentation search is powered by Algolia's DocSearch.
- Run
npm installto install the Node.js dependencies, including Astro (the site builder). - Run
npm run test(or a specific npm script) to rebuild distributed CSS and JavaScript files, as well as our docs assets. - From the root
/bootstrapdirectory, runnpm run docs-servein the command line. - Open http://localhost:9001 in your browser, and voilà.
Learn more about using Astro by reading its documentation.
You can find all our previous releases docs on https://getbootstrap.com/docs/versions/.
Previous releases and their documentation are also available for download.
Please read through our contributing guidelines. Included are directions for opening issues, coding standards, and notes on development.
Moreover, if your pull request contains JavaScript patches or features, you must include relevant unit tests. All HTML and CSS should conform to the Code Guide, maintained by Mark Otto.
Editor preferences are available in the editor config for easy use in common text editors. Read more and download plugins at https://editorconfig.org/.
Get updates on Bootstrap’s development and chat with the project maintainers and community members.
- Follow @getbootstrap on X.
- Read and subscribe to The Official Bootstrap Blog.
- Ask questions and explore our GitHub Discussions.
- Discuss, ask questions, and more on the community Discord or Bootstrap subreddit.
- Chat with fellow Bootstrappers in IRC. On the
irc.libera.chatserver, in the#bootstrapchannel. - Implementation help may be found at Stack Overflow (tagged
bootstrap-5). - Developers should use the keyword
bootstrapon packages which modify or add to the functionality of Bootstrap when distributing through npm or similar delivery mechanisms for maximum discoverability.
For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under the Semantic Versioning guidelines. Sometimes we screw up, but we adhere to those rules whenever possible.
See the Releases section of our GitHub project for changelogs for each release version of Bootstrap. Release announcement posts on the official Bootstrap blog contain summaries of the most noteworthy changes made in each release.
Mark Otto
Jacob Thornton
Thanks to BrowserStack for providing the infrastructure that allows us to test in real browsers!
Thanks to Netlify for providing us with Deploy Previews!
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]
Thank you to all our backers! 🙏 [Become a backer]
Code and documentation copyright 2011-2025 the Bootstrap Authors. Code released under the MIT License. Docs released under Creative Commons.