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.

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.

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.

        
    

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.

        
    

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.