---
title: 'Angular: How to Use Multiple Themes with Material?'
url: https://blog.octoperf.com/angular-how-to-use-multiple-themes-with-material/
date: '2021-01-08'
authors:
- gpereira
categories:
- Development
tags:
- Angular
- Material Design
- SCSS
- CSS
description: A complete tutorial on how to use multiple themes for Angular 11+ and Material Design. Two solutions are discussed with SCSS Mixins and CSS variables.
---
# Angular: How to Use Multiple Themes with Material?
This blog post is a tutorial on **how to use multiple themes for an Angular11+ application with Material Design**.
We start from scratch by [creating a new project ](#create-a-project)and [configuring the themes](#configure-the-themes).
Then we [add a sample Card component](#add-a-sample-component) to see what the themes look like and [create a button to switch between Light and Dark themes](#create-a-theme-switching-button).
Finally, we **discuss two solutions in order to apply a theme to the application body and to a custom component**:
* [Theming using SCSS mixins](#theming-the-application-using-scss-mixins),
* [Theming using CSS variables](#theming-the-application-using-css-variables).
## Prerequisites
The only prerequisite for this guide is to have **installed Angular (version 11 or more)** on your computer.
Check out the [official Angular documentation](https://angular.io/guide/setup-local#prerequisites) to know how to install it.
## Create a Project
So let's start by [creating a new Angular project](https://angular.io/guide/setup-local#create-a-workspace-and-initial-application) called _material-themes_ by executing the command `ng new material-themes` in a terminal:
```shell
> ng new material-themes
? Do you want to enforce stricter type checking and stricter bundle budgets in the workspace?
This setting helps improve maintainability and catch bugs ahead of time.
For more information, see https://angular.io/strict Yes
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? SCSS [ https://sass-lang.com/documentation/syntax#scss ]
CREATE material-themes/README.md (1023 bytes)
CREATE material-themes/.editorconfig (274 bytes)
CREATE material-themes/.gitignore (631 bytes)
CREATE material-themes/angular.json (3777 bytes)
CREATE material-themes/package.json (1205 bytes)
...
CREATE material-themes/e2e/src/app.po.ts (274 bytes)
✔ Packages installed successfully.
Successfully initialized git.
```
__Note:__
> You must select the _SCSS_ option when asked _Which stylesheet format would you like to use?_.
**This creates a sample Angular application without any dependency.** Read the next section to install [the Material Design](https://material.angular.io/) components library.
### Install Material Design
Still in a terminal, execute the command `cd material-themes` to get to the created project and then:
```shell
> ng add @angular/material
? Would you like to share anonymous usage data about this project with the Angular Team at
Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
details and how to change this setting, see https://angular.io/cli/analytics. No
Installing packages for tooling via npm.
Installed packages for tooling via npm.
? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink [ Preview: https://material.angular.io?theme=indigo-pink ]
? Set up global Angular Material typography styles? No
? Set up browser animations for Angular Material? Yes
UPDATE package.json (1271 bytes)
✔ Packages installed successfully.
UPDATE src/app/app.module.ts (423 bytes)
UPDATE angular.json (3979 bytes)
UPDATE src/index.html (494 bytes)
UPDATE src/styles.scss (181 bytes)
```
Several files are updated by this command, we will modify two of them later on:
* Angular being a [Single-page Application](https://en.wikipedia.org/wiki/Single-page_application), the _src/index.html_ is the only HTML file served by a web server for the whole application. All subsequent visual pages are displayed using Javascript,
* **The _src/index.html_ file contains the global styles for our application.** This is where we will define our themes.
### Configure the Themes
Following the official [Theming your Angular Material app](https://material.angular.io/guide/theming#multiple-themes) documentation, we can update the _src/styles.scss_ file to create two color themes:
```scss
@import '~@angular/material/theming';
@include mat-core();
$light-app-theme: mat-light-theme((
color: (
primary: mat-palette($mat-indigo),
accent: mat-palette($mat-pink, A200, A100, A400),
warn: mat-palette($mat-red),
)
));
$dark-app-theme: mat-dark-theme((
color: (
primary: mat-palette($mat-cyan),
accent: mat-palette($mat-blue-gray, A200, A100, A400),
warn: mat-palette($mat-amber),
)
));
@include angular-material-theme($light-app-theme);
.dark-theme {
@include angular-material-color($dark-app-theme);
}
```
Each theme is using its own set of primary/accent/warn colors.
* The `$light-app-theme` is initialized with the SCSS function `mat-light-theme` and will have dark font over white background,
* On the contrary, the `$dark-app-theme-app-theme` is initialized with the SCSS function `mat-mat-dark-theme-theme` and will have light font over dark background,
* **The dark theme is applied to any component inside an HTML tag with the `dark-theme` CSS class.**
## Components
To apply the dark theme to the whole application, the trick is to [add the _dark-theme_ class](#programmatically-switch-to-dark-theme) to the root `` tag inside the `src/index.html` file.
But first let's [add a sample component to our application](#add-a-sample-component) so that we can see what our themes looks like.
### Add a Sample Component
The easiest way to do it is to **copy/paste an example Card component** taken from the [Material documentation examples](https://material.angular.io/components/card/examples) (plus I love Shiba dogs!):
Update the _src/app/app.component.html_ file to replace its default content by the Material card component:
```html
Shiba InuDog Breed
The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan.
A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally
bred for hunting.
```
Don't forget to also update the _src/app/app.component.scss_ styles file:
```scss
.example-card {
max-width: 400px;
}
.example-header-image {
background-image: url('https://material.angular.io/assets/img/examples/shiba1.jpg');
background-size: cover;
}
```
And more importantly to **add _MatCardModule_ and _MatButtonModule_ modules to the application module imports (_src/app/app.module.ts_)**:
```ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatCardModule,
MatButtonModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
```
Time to check the result: type the command `ng serve --open` in your terminal.
The application should automatically open in your preferred web browser and display the following content:

#### Programmatically Switch to Dark Theme
To check what it looks like in dark mode simply update the _src/index.html_ file to set the _dark-theme_ class on the html tag:
```html
...
```
The application should now display the card component with a darkish background:

### Create a Theme Switching Button
**The theme selection should be up to the user though.**
Start by reverting the previous modifications to the _src/index.html_ file in order to use the light theme by default.
Then create a _theme-switch_ component to allow the dynamic theme selection with the command `ng generate component theme-switch`.
```shell
> ng generate component theme-switch
CREATE src/app/theme-switch/theme-switch.component.scss (0 bytes)
CREATE src/app/theme-switch/theme-switch.component.html (27 bytes)
CREATE src/app/theme-switch/theme-switch.component.spec.ts (662 bytes)
CREATE src/app/theme-switch/theme-switch.component.ts (299 bytes)
UPDATE src/app/app.module.ts (672 bytes)
```
This component is a toggle button that sets/removes the _dark-theme_ on the root html tag when clicked.
Update the file _src/app/theme-switch/theme-switch.component.html_ to:
```html
LightDark
```
Update the file _src/app/theme-switch/theme-switch.component.ts_ to:
```ts
import {Component, Inject} from '@angular/core';
import {DOCUMENT} from '@angular/common';
@Component({
selector: 'app-theme-switch',
templateUrl: './theme-switch.component.html',
styleUrls: ['./theme-switch.component.scss']
})
export class ThemeSwitchComponent {
private static readonly DARK_THEME_CLASS = 'dark-theme';
private static readonly DARK_THEME_LIGHT = 'light';
private static readonly DARK_THEME_DARK = 'dark';
public theme: string;
constructor(@Inject(DOCUMENT) private document: Document) {
this.theme = this.document.documentElement.classList.contains(ThemeSwitchComponent.DARK_THEME_CLASS) ? ThemeSwitchComponent.DARK_THEME_DARK : ThemeSwitchComponent.DARK_THEME_LIGHT;
}
public selectDarkTheme(): void {
this.document.documentElement.classList.add(ThemeSwitchComponent.DARK_THEME_CLASS);
this.theme = ThemeSwitchComponent.DARK_THEME_DARK;
}
public selectLightTheme(): void {
this.document.documentElement.classList.remove(ThemeSwitchComponent.DARK_THEME_CLASS);
this.theme = ThemeSwitchComponent.DARK_THEME_LIGHT;
}
}
```
The _document_ is injected in the component constructor and the `` element is retrieved by accessing the [_document.documentElement_ field](https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement).
Then, adding or removing the _dark-theme_ CSS class is simply done by using the [classList property](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList).
__Notes:__
> Don't forget to add the _MatButtonToggleModule_ module to the _src/app/app.module.ts_ file imports.
>
> You also need to update the _src/app/app.component.html_ file to include the created _theme-switch_ component: ``.
Open the web application and click on the theme switch button to select the dark/light mode:

**There is one issue though: the background remains white when switching to the dark theme!**
Let's fix this using SCSS Mixins!
## Theming the Application Using SCSS Mixins
Using SCSS Mixins is the recommended way to apply themes to your application in the [Material documentation](https://material.angular.io/guide/theming-your-components).
### Theming the App Background
Update the _src/styles.scss_ file to:
* Create a _body-theme_ mixin,
* Use it both in the default light theme and the dark one.
```scss
@import '~@angular/material/theming';
...
@mixin body-theme($theme) {
$_background: map-get($theme, background);
$app-background-color: mat-color($_background, background);
body {
background-color: $app-background-color;
}
}
@include angular-material-theme($light-app-theme);
@include body-theme($light-app-theme);
.dark-theme {
@include angular-material-color($dark-app-theme);
@include body-theme($dark-app-theme);
}
```
**The _body-theme_ mixin gets the default application background color from the given _$theme_ parameter by using the _mat-get_ and _mat-color_ functions imported from the material library.**
The application in dark mode should now display a dark background as well as a dark card component:

### Theming your Own Component
In this section we see **how to apply theme colors to one of our own component**.
#### Create the Component
Of course **the first step is to create a component of our own**. Here a dummy teapot component that displays "I'm a teapot!" in a bordered panel.
Generate it using the following command:
```shell
> ng generate component teapot
CREATE src/app/teapot/teapot.component.scss (0 bytes)
CREATE src/app/teapot/teapot.component.html (21 bytes)
CREATE src/app/teapot/teapot.component.spec.ts (626 bytes)
CREATE src/app/teapot/teapot.component.ts (276 bytes)
UPDATE src/app/app.module.ts (878 bytes)
```
Update the _src/app/teapot/teapot.component.html_ file:
```html
I'm a teapot!
```
As well as the _src/app/teapot/teapot.component.scss_ one:
```scss
p {
margin-bottom: 1rem;
padding: 2rem;
display: block;
border: 1px solid blue;
background-color: grey;
}
```
Finally, update the App component html to include our component (_src/app/app.component.html_):
```html
```
The application should look like this:

#### Create a Theme Mixin
**Time to apply color theming to this newly created component using SCSS mixin!**
First strip the file _src/app/teapot/teapot.component.scss_ of color related styles:
```scss
p {
margin-bottom: 1rem;
padding: 2rem;
display: block;
}
```
Then update the _src/styles.scss_ root styles file to add a new mixin dedicated to our teapot component:
```scss
// Teapot Theming
@mixin teapot-theme($theme) {
$_background: map-get($theme, background);
$_foreground: map-get($theme, foreground);
$background-color: mat-color($_background, background);
$foreground-color: mat-color($_foreground, text);
$primary: map-get($theme, primary);
p.teapot {
border: 1px solid mat-color($primary);
background-color: darken($background-color, 10%);
color: $foreground-color;
}
}
```
The border now uses the primary color of the current theme.
The text is displayed using the theme foreground color, and the background matches the theme's.
**You should also update the default and dark themes to include this mixin:**
```scss
@include angular-material-theme($light-app-theme);
@include body-theme($light-app-theme);
@include teapot-theme($light-app-theme);
.dark-theme {
@include angular-material-color($dark-app-theme);
@include body-theme($dark-app-theme);
@include teapot-theme($dark-app-theme);
}
```
Reopen the application: switching from light to dark theme should update the teapot component accordingly:


## Theming the Application Using CSS Variables
**IMO using SCSS mixins is not ideal to handle multiple custom Material themes!**
### Theming Choice Considerations
First you have all your theme related styles in a single _src/styles.scss_ file. It can become quite big if you have many custom components.
The other solution is to split this file in several smaller files, for example:
* A _material-variables.scss_ file that imports the material theming functions (`@import '~@angular/material/theming';`) and declare the two themes (`$light-app-theme: mat-light-theme(...) $dark-app-theme: mat-dark-theme(...)`),
* A _material-themes.scss_ file that includes the mat-core with `@include mat-core();` and includes the theme styles for both the light and dark mode,
* An _app.scss_ that imports the _material-themes.scss_ file (this must be done only once in the whole application) and declares other custom global themes.
Then, each custom component that needs to get color values from the Material theme can include the _material-variables.scss_ file and create the theme mixin here.
This is harder to set up though.
**And you still have to get colors from the given theme for every custom component!** This is tedious and creates many repetitions in your styles.
### A Single Mixin that Declares CSS Variables
The idea is to have **a single mixin dedicated to theme colors that initialize CSS3 variables**.
CSS variables are also known as [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) or cascading variables.
So let's update the _src/styles.scss_ file to create it:
```scss
@import '~@angular/material/theming';
@include mat-core();
...
@mixin theme-colors($theme) {
$_background: map-get($theme, background);
$_foreground: map-get($theme, foreground);
$_primary: map-get($theme, primary);
$background-color: mat-color($_background, background);
$foreground-color: mat-color($_foreground, text);
$primary-color: mat-color($_primary);
--app-background-color: #{$background-color};
--app-background-dark-color: #{darken($background-color, 10%)};
--app-foreground-color: #{$foreground-color};
--app-primary-color: #{$primary-color};
}
```
Here, the _theme-colors_ mixin is created:
* It fetches the various colors from the Material theme using _map-get_ and _mat-color_ functions,
* It initializes several CSS variables with the syntax `--my-var: value`:
* The value is set using [String interpolation](https://sass-lang.com/documentation/interpolation) (The `#{...}` around the value), otherwise the SCSS variable name is written in the variable instead of its value,
* The _darken_ SCSS function is used to create a darker shade of the theme background.
This mixin is used a usual in the default light theme as well as in the dark one if the CSS class _dark-theme_ is set:
```scss
:root {
@include angular-material-color($light-app-theme);
@include theme-colors($light-app-theme);
}
.dark-theme {
@include angular-material-color($dark-app-theme);
@include theme-colors($dark-app-theme);
}
```
__Note:__
> Here we use [the `:root` syntax](https://developer.mozilla.org/en-US/docs/Web/CSS/:root). It is a CSS pseudo-class that matches the root element of a tree representing the document (The `` element in our case).
### Theming the Body Background Color
The body background color now uses the previously created CSS variable with the syntax `var(--my-var)`:
```scss
body {
background-color: var(--app-background-color);
}
```
### Theming our Custom Component
You can also update the style of the teapot component (_src/app/teapot/teapot.component.scss_) to use these variables:
```scss
p {
margin-bottom: 1rem;
padding: 2rem;
display: block;
border: 1px solid var(--app-primary-color);
background-color: var(--app-background-dark-color);
color: var(--app-foreground-color);
}
```
**The big advantage is that all the style for this component is now located in a single file, making it easier to maintain**.
Also, the variable values are only fetched from the theme once.
There are a few drawbacks to this approach though:
* You must declare all values in the mixin: for instance it is not possible to do `darken(var(--app-background-color), 10%)` as _darken_ is an SCSS function executed when the files are compiled to CSS,
* It can be hard to distinguish SCSS variables (compiled: their value is fixed during runtime) from CSS variables (that can be updated at runtime and are evaluated by the web browser).
* I don't know in what proportions but the CSS variables have an impact on performances when the browser renders your application.
## Conclusion
__Sources:__
> The source code for this guide is available on GitHub at [material-themes CSS variables](https://github.com/geraldpereira/material-themes/tree/master) for the version that uses CSS variables.
> The version based on SCSS mixins is available at [material-themes mixins](https://github.com/geraldpereira/material-themes/tree/mixins).
**So what's your opinion regarding multiple themes usage in an Angular application?** Would you rather use SCSS mixins or CSS variables? A mix of both maybe?