Search code examples
javascriptangularsassbootstrap-5

How to dynamically change Bootstrap v5.3 primary color at runtime in Angular v17?


I am working on an Angular application that uses Bootstrap for styling. I want to allow users to select a theme color, and dynamically update the Bootstrap primary color (--bs-primary) at runtime without reloading the page.

Currently, Bootstrap’s primary color is defined in SCSS like this:

$primary: #0d6efd; 
@import "bootstrap/scss/bootstrap";

However, this approach requires recompilation, and I need a way to change the primary color dynamically via JavaScript or TypeScript.

What I Have Tried CSS Variables I attempted to override the Bootstrap primary color using CSS variables:

:root {
    --bs-primary: #{$primary};
}

But this does not seem to work for all Bootstrap components like buttons and alerts.

Using JavaScript to Update Variables I also tried updating CSS variables dynamically in TypeScript:

  changeThemeColor(color: string): void {
    document.documentElement.style.setProperty('--bs-primary', color);
    const primaryRgb = this.hexToRgb(color);
    if (primaryRgb) {
      document.documentElement.style.setProperty('--bs-primary-rgb', `${primaryRgb.r}, ${primaryRgb.g}, ${primaryRgb.b}`);
    }
  }

However, this change above its only the span with text-primary that gets to reflect the changes of the new color and the button does not

<span class="text-primary">Primary Text</span>
<button class="btn btn-primary">Primary Button</button>

Solution

  • These are the styles of the btn-primary, As you can see they are not derived from variables but defined directly.

    .btn-primary {
        --bs-btn-color: #fff;
        --bs-btn-bg: #0d6efd;
        --bs-btn-border-color: #0d6efd;
        --bs-btn-hover-color: #fff;
        --bs-btn-hover-bg: rgb(11.05, 93.5, 215.05);
        --bs-btn-hover-border-color: rgb(10.4, 88, 202.4);
        --bs-btn-focus-shadow-rgb: 49, 132, 253;
        --bs-btn-active-color: #fff;
        --bs-btn-active-bg: rgb(10.4, 88, 202.4);
        --bs-btn-active-border-color: rgb(9.75, 82.5, 189.75);
        --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
        --bs-btn-disabled-color: #fff;
        --bs-btn-disabled-bg: #0d6efd;
        --bs-btn-disabled-border-color: #0d6efd;
    }
    

    You can still override them with the below method. The font color of the first button is derived from '--bs-primary-rgb' so you can override this using your method.

    The code will look something like below:

    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { CommonModule } from '@angular/common';
    @Component({
      selector: 'app-root',
      imports: [CommonModule],
      template: `
        <span class="text-primary">Primary Text</span>
        <button class="btn btn-primary" [ngStyle]="color ? {
          '--bs-primary-rgb': color,
            '--bs-btn-bg': color,
            '--bs-btn-border-color': color,
        } : {}">Primary Button</button>
        <button (click)="changeThemeColor('#DFDFDF')"> change color</button>
      `,
    })
    export class App {
      color: string | undefined;
      changeThemeColor(color: string): void {
        this.color = color;
        ['--bs-primary-rgb'].forEach((item: string) => {
          document.documentElement.style.setProperty(item, color);
        });
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo