Igor Simic
3 years ago

Angular Material create theme switch component




How to create theme switcher for Angular Material?  We will create component which will do a theme switching from black to white theme.  We will store info about selected theme in local storage and once when user set the theme it will be applied on every next visit of the page.

First let's generate component:
ng g c Components/ThemeSwitcher

This component should look like this:
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-theme-switcher',
  templateUrl: './theme-switcher.component.html',
  styleUrls: ['./theme-switcher.component.sass']
})
export class ThemeSwitcherComponent implements OnInit {
  // let's define default theme
  themeColor = 'light-theme';

  constructor() { }

  ngOnInit() {

    this.setDefaultTheme();

}

setDefaultTheme(){

      // if theme is stored in storage - use it

      if(localStorage.getItem('pxTheme')){

          //set theme color to one from storage
          this.themeColor = localStorage.getItem('pxTheme');

          //add that class to body
          const body = document.getElementsByTagName('body')[0];
          body.classList.add(this.themeColor);
      }
}

themeSwitcher(){

      const body = document.getElementsByTagName('body')[0];
      body.classList.remove(this.themeColor);

      // switch theme
      (this.themeColor == 'light-theme')?this.themeColor = 'dark-theme':this.themeColor = 'light-theme';

      body.classList.add(this.themeColor);

      //save it to local storage

      localStorage.setItem('pxTheme',this.themeColor);
}

}
Create HTML for switching the themes in theme-switcher.component.html
<button mat-icon-butto mat-button="" (click)="themeSwitcher()">
  <mat-icon>format_color_fill</mat-icon>
</button>

Now let's create black and white themes in styles.sass file:
//include material theming
@import '[email protected]/material/theming';
@include mat-core();


// Define the light theme
$light-app-primary: mat-palette($mat-indigo);
$light-app-accent:  mat-palette($mat-pink, A200, A100, A400);
$light-app-theme:   mat-light-theme($light-app-primary, $light-app-accent);

// Include the light theme styles.
@include angular-material-theme($light-app-theme);


// Define an dark theme.
$dark-primary: mat-palette($mat-blue-grey);
$dark-accent:  mat-palette($mat-amber, A200, A100, A400);
$dark-warn:    mat-palette($mat-deep-orange);
$dark-theme:   mat-dark-theme($dark-primary, $dark-accent, $dark-warn);

// themes will be switched based on class names, angular will switch classes which will trigger the theme change
.dark-theme
  @include angular-material-theme($dark-theme)

.light-theme
  @include angular-material-theme($light-app-theme)

if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body)
<body class="mat-app-background">
Add ThemeSwitcherComponent to providers inside of app.module.ts
providers: [ThemeSwitcherComponent]
You may notice that stored theme is only loaded when we page is loaded from home route, if we go to some other route and make a page load, theme is not switched to already stored theme setting. To fix this, we have to import ThemeSwitcherComponent to app.component.ts so it can be triggered on every request. Open app.component.ts and add it:
import {ThemeSwitcherComponent} from './Components/theme-switcher/theme-switcher.component';
....
constructor(
    public themeSwitch: ThemeSwitcherComponent
    ....
 ){}

// call theme switch on init
ngOnInit(){
  this.themeSwitch.setDefaultTheme();
}

Now, correct theme will be set no matter which route we hit on first pageload.

More info you can get on official Angular Material site