angularsassangular-materialmaterial3angular-theming

How to avoid style duplication when including themes?


I have updated my Angular application to Angular 19.2, and also to Angular Material 19.2.

I have created color palettes by running ng generate @angular/material:theme-color, to generate the file _theme-colors.scss.

In my style sheet styles.scss I have:

@use '@angular/material' as mat;
@use '_theme-colors.scss' as my-theme;

$my-theme: mat.define-theme((
  color: (
    theme-type: light,
    primary: my-theme.$primary-palette,
    tertiary: my-theme.$tertiary-palette
  ),
  typography: (
    brand-family: 'Montserrat',
  ),
  density: (
    scale: 0
  )
));

html {
  color-scheme: light;

  @include mat.core-theme($my-theme);
  // @include mat.all-component-themes($my-theme);
  @include mat.button-theme($my-theme);
  @include mat.dialog-theme($my-theme);
  @include mat.divider-theme($my-theme);
  @include mat.sidenav-theme($my-theme);
  @include mat.slide-toggle-theme($my-theme);

  .primary-button {
    @include mat.button-color($my-theme, $color-variant: primary);
  }

  .secondary-button {
    @include mat.button-color($my-theme, $color-variant: secondary);
  }

  .tertiary-button {
    @include mat.button-color($my-theme, $color-variant: tertiary);
  }

}

$my-dark-theme: mat.define-theme((
  color: (
    theme-type: dark,
    primary: my-theme.$primary-palette,
    tertiary: my-theme.$tertiary-palette,
  ),
  typography: (
    brand-family: 'Montserrat',
  ),
  density: (
    scale: 0
  )
));

html.dark-theme {
  color-scheme: dark;

  @include mat.core-theme($my-dark-theme);
  // @include mat.all-component-themes($my-dark_theme);
  @include mat.button-theme($my-dark-theme);
  @include mat.dialog-theme($my-dark-theme);
  @include mat.divider-theme($my-dark-theme);
  @include mat.sidenav-theme($my-dark-theme);
  @include mat.slide-toggle-theme($my-dark-theme);

  .primary-button {
    @include mat.button-color($my-dark-theme, $color-variant: primary);
  }

  .secondary-button {
    @include mat.button-color($my-dark-theme, $color-variant: secondary);
  }

  .tertiary-button {
    @include mat.button-color($my-dark-theme, $color-variant: tertiary);
  }
}

plus a bunch of other stuff.

I had thought that I was doing everything correctly, but when I build the project, I get a whole lot of warnings similar to the following:

▲ [WARNING] The same base theme styles are generated multiple times. Read more about how style duplication can be avoided in a dedicated guide. https://v18.material.angular.io/guide/duplicate-theming-styles [plugin angular-sass]

    angular:styles/global:styles:1:8:
      1 │ @import 'src/styles.scss';
        ╵         ~~~~~~~~~~~~~~~~~

  node_modules\@angular\material\core\theming\_theming.scss 149:7  -check-duplicate-theme-styles-v1()
  node_modules\@angular\material\core\theming\_theming.scss 58:5   private-check-duplicate-theme-styles()
  node_modules\@angular\material\core\_core-theme.scss 109:3       theme()
  src\styles.scss 61:3                                             root stylesheet
  

In fact I get three different warnings:

Each of these warnings occurs 6 times, at the 6 @include statements for the dark theme.

Since I am obviously not doing everything correctly, what is the correct way to include the themes for Angular Material 3?


Solution

  • There is a great guide explaining about duplication of color, density and typography, which is actually very easy to do.

    Avoiding duplicated theming styles - v18 Guide (removed in 19+ Docs)

    Example of non duplication (Others provided in the link above):

    @use '@angular/material' as mat;
    
    ...
    @include mat.all-component-themes($light-theme);
    
    .dark-theme {
      // This mixin only generates the color styles now.
      @include mat.all-component-colors($dark-theme);
    }
    

    So all we need to do is for example, instead of mat.button-theme we need to use mat.button-color and just change the color system, instead of define the entire theme again (Which will include densities and typographies - which cause the duplicates).

    Before:

    html.dark-theme {
      color-scheme: dark;
    
      @include mat.core-theme($my-dark-theme);
      // @include mat.all-component-themes($my-dark_theme);
      @include mat.button-theme($my-dark-theme);
      @include mat.dialog-theme($my-dark-theme);
      @include mat.divider-theme($my-dark-theme);
      @include mat.sidenav-theme($my-dark-theme);
      @include mat.slide-toggle-theme($my-dark-theme);
      ...
    

    After:

    html.dark-theme {
      color-scheme: dark;
    
      @include mat.core-color($my-dark-theme);
      // @include mat.all-component-themes($my-dark_theme);
      @include mat.button-color($my-dark-theme);
      @include mat.dialog-color($my-dark-theme);
      @include mat.divider-color($my-dark-theme);
      @include mat.sidenav-color($my-dark-theme);
      @include mat.slide-toggle-color($my-dark-theme);
      ...
    

    Full Code:

    @use '@angular/material' as mat;
    @use '_theme-colors.scss' as my-theme;
    
    $my-theme: mat.define-theme(
      (
        color: (
          theme-type: light,
          primary: my-theme.$primary-palette,
          tertiary: my-theme.$tertiary-palette,
        ),
        typography: (
          brand-family: 'Montserrat',
        ),
        density: (
          scale: 0,
        ),
      )
    );
    
    html {
      color-scheme: light;
    
      @include mat.core-theme($my-theme);
      // @include mat.all-component-themes($my-theme);
      @include mat.button-theme($my-theme);
      @include mat.dialog-theme($my-theme);
      @include mat.divider-theme($my-theme);
      @include mat.sidenav-theme($my-theme);
      @include mat.slide-toggle-theme($my-theme);
    
      .primary-button {
        @include mat.button-color($my-theme, $color-variant: primary);
      }
    
      .secondary-button {
        @include mat.button-color($my-theme, $color-variant: secondary);
      }
    
      .tertiary-button {
        @include mat.button-color($my-theme, $color-variant: tertiary);
      }
    }
    
    $my-dark-theme: mat.define-theme(
      (
        color: (
          theme-type: dark,
          primary: my-theme.$primary-palette,
          tertiary: my-theme.$tertiary-palette,
        ),
        typography: (
          brand-family: 'Montserrat',
        ),
        density: (
          scale: 0,
        ),
      )
    );
    
    html.dark-theme {
      color-scheme: dark;
    
      @include mat.core-color($my-dark-theme);
      // @include mat.all-component-themes($my-dark_theme);
      @include mat.button-color($my-dark-theme);
      @include mat.dialog-color($my-dark-theme);
      @include mat.divider-color($my-dark-theme);
      @include mat.sidenav-color($my-dark-theme);
      @include mat.slide-toggle-color($my-dark-theme);
    
      .primary-button {
        @include mat.button-color($my-dark-theme, $color-variant: primary);
      }
    
      .secondary-button {
        @include mat.button-color($my-dark-theme, $color-variant: secondary);
      }
    
      .tertiary-button {
        @include mat.button-color($my-dark-theme, $color-variant: tertiary);
      }
    }
    

    Stackblitz Demo