Dark mode with Angular Material

A dark mode can improve the accessibility of your website. In this article I want to show you how to implement a dark mode with Angular Material. This will include detection of the preferred mode of the browser and also a toggle button to switch between the modes. The last selection will be stored in the localstorage and can be restored the next time the website is loaded.

Creating the stylesheet

First we add the following code to our styles.scss file.

styles.scss @use '@angular/material' as mat; $custom-typography: mat.define-typography-config($font-family: 'Roboto, sans-serif'); $custom-primary-palette: mat.define-palette(mat.$indigo-palette); $custom-accent-palette: mat.define-palette(mat.$grey-palette); $custom-warn-palette: mat.define-palette(mat.$red-palette); $custom-light-theme: mat.define-light-theme(( color: ( primary: $custom-primary-palette, accent: $custom-accent-palette, warn: $custom-warn-palette ), typography: $custom-typography )); $custom-dark-theme: mat.define-dark-theme(( color: ( primary: $custom-primary-palette, accent: $custom-accent-palette, warn: $custom-warn-palette ), typography: $custom-typography )); @include mat.core(); @include mat.all-component-themes($custom-light-theme); @include mat.all-component-typographies($custom-light-theme); body { &.dark-mode { // Change material colors @include mat.all-component-colors($custom-dark-theme); // Change custom elements colors .hyperlink-button { &:hover { color: mat.get-theme-color($custom-dark-theme, foreground, text) !important; } } } }

This code will create a light and a dark theme. Whenever the class "dark-mode" is applied to the body element, the dark mode will be active.

Implementing a service

Next we will create a service that can be used to detect and change the light or dark mode.

dark-mode.service.ts @Injectable({ providedIn: 'root' }) export class DarkModeService { private isDarkMode: boolean = false; private readonly localStorageKey = 'my-app.dark-mode'; private readonly darkModeCssClassName = 'dark-mode'; constructor(@Inject(DOCUMENT) private readonly document: Document) { } public initialize(): void { const prefersDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; const item = localStorage.getItem(this.localStorageKey); const savedDarkMode = item ? JSON.parse(item) as boolean : null; if(savedDarkMode !== this.isDarkMode) { this.toggle(); } else if (savedDarkMode == null && prefersDarkMode !== this.isDarkMode) { this.toggle(); } } public toggle() : void { this.isDarkMode = this.document.body.classList.toggle(this.darkModeCssClassName); localStorage.setItem(this.localStorageKey, JSON.stringify(this.isDarkMode)); } public getIsDarkMode(): boolean { return this.isDarkMode; } }

In our app.component.ts file we just have to call the initialize() method to detect and apply the mode when the application is loaded the first time.

app.component.ts @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { constructor(private readonly darkModeService: DarkModeService) { this.darkModeService.initialize(); } }

Creating a slider

The last step is to create a ui-component that can be used to toggle between light and dark mode manually.

dark-mode-slider.component.html <div> <mat-icon class="me-2">{{ isDarkMode ? 'bedtime' : 'wb_sunny' }}</mat-icon> <mat-slide-toggle [checked]="isDarkMode" color="primary" (click)="changeDarkMode()"> </mat-slide-toggle> </div> dark-mode-slider.component.ts @Component({ selector: 'app-dark-mode-slider', templateUrl: './dark-mode-slider.component.html', styleUrls: ['./dark-mode-slider.component.scss'] }) export class DarkModeSliderComponent { constructor(private readonly darkModeService: DarkModeService) { } protected changeDarkMode() { this.darkModeService.toggle(); } protected get isDarkMode(): boolean { return this.darkModeService.getIsDarkMode(); } }

Summary

I hope I could help you in this article to implement your own dark mode very easily.