ng-bootstrap HomeBasicAlertFormsFloating labelsInput groupMulti-rangeRangePhone inputSelectRadioCheckboxDatepickerTimepickerDateTime pickerContainersGridCardTab controlRatingBadgeBreadcrumbButton groupButton typeCalendarMarqueeList groupTreeviewTree selectTableClosePaginationPlaceholderSpinnerColor pickerProgress barFor directiveIconOverlaysModalsOffcanvasTooltipToastPopoverDropdownTypeaheadContext menuShellDropdown menu (WC)AdvancedCopyCode snippetPipesTrust-htmlSplit-stringLinifySlugifyWord-countFont-colorHas-propertyToggle buttonsSticky footerAutofocusTrackByAsync HostBindingInstance ofIs interfaceResizableOrdinal numbersMarkdownParallaxPriority navigationScrollspyFile uploadSignature padLazy-loading componentsUser-agentNavigation lockNavigation lock (master/detail)EnterpriseCarouselSchedulerTimelineDockRibbonTile managerDatatablesFile managerQuery builderOTP inputNavbarSplitterAccordionChartsAnimationsSlide up/downFade in/outColor transitionAdditional samplesCollapseFocusTrapDrag-dropTree-select drag-dropQR-code viewerStepperThemingAnchor scrollingSection 1Section 2Section 3Section 4Section 522.15.0

Theming & dark mode

Bootstrap 5.3 ships a built-in color-mode system based on the data-bs-theme attribute. @mintplayer/ng-bootstrap adds a tiny service on top that owns the user's preference, persists it, and resolves auto via prefers-color-scheme — and exposes it as Angular signals.

Three primitives, two recipes.
  • To switch light/dark/auto at runtime, flip data-bs-theme on <html>. BsThemeService does this for you.
  • To customize colors at build time, override Bootstrap's SCSS variables before@importing the library's bundle.
  • To customize colors at runtime, set the corresponding --bs-* CSS variables via document.documentElement.style.setProperty(...).

Build-time customization (SCSS)

Bootstrap's design tokens are SCSS variables. Override them before importing the library's SCSS bundle to bake your palette into the compiled CSS — no runtime cost. This is the right approach when your brand colors are fixed.

All standard Bootstrap variables ($primary, $body-bg, $navbar-padding-y, …) are available — see the Bootstrap Sass reference for the full list.

Runtime customization (CSS variables)

Bootstrap also exposes most tokens as --bs-* CSS custom properties. Mutating them at runtime lets you build features like a per-user theme picker without re-deploying. The components pick up the change on the next paint.

Live demo

What changes when you Apply: every component below uses --bs-primary — the swatch, the buttons, the alert, the link, and the progress bar all swap in lockstep with the CSS variable.

Note about .btn-primary and .btn-outline-primary. Vanilla Bootstrap 5.3 bakes literal color values into each button variant's scoped --bs-btn-* variables — so mutating --bs-primary at runtime does not reach buttons in a stock Bootstrap project. @mintplayer/ng-bootstrap ships a small override that re-binds .btn-primary and .btn-outline-primary to var(--bs-primary) (with color-mix() for hover / active shades), which is why the buttons above swap with the rest. If you want the same behavior for .btn-success, .btn-danger, etc., add an analogous block in your own stylesheet.
swatch
badgelink-primary

Per-component variables

Each Bootstrap component also defines its own scoped --bs-* variables. Tweaking these lets you restyle one component without touching the global palette. A few common ones:

ComponentVariableEffect
Navbar--bs-navbar-colorDefault link/text color
Navbar--bs-navbar-active-colorActive link color
Navbar--bs-navbar-brand-colorBrand text color
Card--bs-card-bgCard surface color
Card--bs-card-border-colorCard border
Card--bs-card-cap-bgCard header / footer surface
Dropdown--bs-dropdown-bgDropdown menu surface
Dropdown--bs-dropdown-link-hover-bgHovered item background
Modal--bs-modal-bgModal surface
Modal--bs-modal-header-border-colorHeader separator
Button--bs-btn-bgButton surface (scope to a selector)
Button--bs-btn-border-colorButton border
Body / global--bs-body-bgPage background
Body / global--bs-body-colorDefault text color
Body / global--bs-border-colorDefault border color
Body / global--bs-primary  /  --bs-primary-rgbPrimary brand color (pair both for opacity-aware usage)

The canonical list is component-specific and may shift between Bootstrap versions — see the CSS variables reference for the authoritative table.

Switching mode at runtime

BsThemeService is a signal-first service that owns the user's chosen mode and writes the resolved value to <html data-bs-theme>. auto resolves to light or dark via matchMedia('(prefers-color-scheme: dark)') and live-updates when the OS preference changes.

Live demo

mode: auto   effectiveMode: light

Adaptive navbar

To make <bs-navbar> follow the page theme automatically, pass [color]="'body-tertiary'". The navbar emits bg-body-tertiary (no data-bs-theme override) and Bootstrap's --bs-tertiary-bg CSS variable swaps with the page theme — giving a slightly tinted, theme-aware navbar in both light and dark.

[color] accepts either a Color enum value (Color.dark, Color.primary, …) or a string utility-class suffix ('body-tertiary', 'body-secondary'). Enum values also pin the navbar's own theme via data-bs-theme; string suffixes let the page theme cascade through. null emits no background — fully transparent navbar that inherits everything from the page.

Custom variants beyond light & dark

The mode string is open-ended. Author a custom [data-bs-theme="…"] block in your global SCSS, then activate it via setMode('your-variant'). Known values (auto, light, dark) keep autocomplete; arbitrary strings also compile.

auto only resolves to light or dark.prefers-color-scheme doesn't know about custom variants — they must be set explicitly. Switching to auto while the user is on a custom variant returns them to the system preference.

SSR & no-flash integration

Server-rendered HTML has no data-bs-theme attribute by default — which means dark-mode users see a brief light-mode flash before the Angular service runs. Fix it with a tiny pre-boot<script> in <head>, before any <link rel="stylesheet">. The script reads localStorage and prefers-color-scheme, then writes the attribute synchronously — before the browser has resolved any CSS.

The storage key ('bs-theme-mode') must match the BS_THEME_STORAGE_KEY constant exported by @mintplayer/ng-bootstrap/theming. The script can't import the constant because it runs before any module loads — keep the two literals in lockstep.

API reference

theme.mode
Signal<'auto' | 'light' | 'dark' | string> — the user's authored preference. Read-only; use setMode() to change.
theme.effectiveMode
Signal<'light' | 'dark' | string> — the resolved value. auto resolves to light or dark via matchMedia('(prefers-color-scheme: dark)'); explicit values pass through unchanged.
theme.setMode(m)
Set the mode. Persists to localStorage and updates <html data-bs-theme>.
BS_THEME_STORAGE_KEY
The localStorage key ('bs-theme-mode') used by the service. Exposed for the pre-boot script.