Angular Material Components Theming System: Complete Guide

Angular Material Components Theming System: Complete Guide

# Create a custom theme A **theme file** is a SASS file that uses Angular Material SASS mixins to produce color and typography CSS styles. Let’s jump to `src/styles.scss` file and have a look at our theme: ```scss @use '@angular/material' as mat; @include mat.core(); $my-app-primary: mat.define-palette(mat.$indigo-palette); $my-app-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); $my-app-warn: mat.define-palette(mat.$red-palette); $my-app-theme: mat.define-light-theme(( color: ( primary: $my-app-primary, accent: $my-app-accent, warn: $my-app-warn, ) )); @include mat.all-component-themes($my-app-theme); html, body { height: 100%; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } ``` Let’s break the above code into pieces to understand more. ## The `core` mixin ```scss @include mat.core(); ``` The first thing in the theme file you will notice is the `core` mixin. Angular Material defines a mixin named `core` that includes prerequisite styles for common features used by multiple components, such as [ripples](https://github.com/angular/components/blob/534b54625a5ecbb477e5e4eb1d282d8aad2e77e5/src/material/core/_core.scss#L9C4-L9C4). ## Defining a theme Angular Material represents a theme as a SASS map that contains your color and typography choices. Colors are defined through a palette. A palette is a collection of colors representing a portion of color space. Each value in this collection is called a hue. In Material Design, each hue in a palette has an identifier number. These identifier numbers include 50, and then each 100 value between 100 and 900. The numbers order hues within a palette from lightest to darkest. Angular Material represents a palette as a SASS map. ### The `define-palette` function ```scss $my-app-primary: mat.define-palette(mat.$indigo-palette); $my-app-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); // The "warn" palette is optional and defaults to red if not specified. $my-app-warn: mat.define-palette(mat.$red-palette); ``` To construct a theme, 2 palettes are required: `primary` and `accent`, and `warn` palette is optional. The `define-palette` SASS function accepts a color palette, as well as four optional hue numbers. These four hues represent, in order: the `default` hue, a `lighter` hue, a `darker` hue, and a `text` hue. Components use these hues to choose the most appropriate color for different parts of themselves. In our example, we have used predefined palettes, i.e. `$indigo-palette`, `$pink-palette` and `$red-palette`. You can check out other palettes at the Angular Material GitHub [repo’s file](https://github.com/angular/components/blob/main/src/material/core/theming/_palette.scss): ```scss // src/material/core/theming/_palette.scss // content reduced for brevity $red-palette: ( 50: #ffebee, 100: #ffcdd2, 200: #ef9a9a, 300: #e57373, // ... contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, // ... ) ); $pink-palette: ( 50: #fce4ec, 100: #f8bbd0, 200: #f48fb1, 300: #f06292, // ... contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, // ... ) ); ``` ### Create your own palette You can also create your own palettes by defining a SASS map like below: ```scss $tw-indigo-palette: ( 50: rgb(238 242 255), 100: rgb(224 231 255), 200: rgb(199 210 254), 300: rgb(165 180 252), // ... continues to 900 contrast: ( 50: rgba(black, 0.87), 100: rgba(black, 0.87), 200: rgba(black, 0.87), 300: white, // ... continues to 900 ) ); ``` ### The `define-light-theme` function ```scss $my-app-theme: mat.define-light-theme(( color: ( primary: $my-app-primary, accent: $my-app-accent, warn: $my-app-warn, ) )); ``` You can construct a theme by calling either `define-light-theme` or `define-dark-theme` with the result from `define-palette`. The choice of a light versus a dark theme determines the background and foreground colors used throughout the components. ### Applying a theme to components ```scss @include mat.all-component-themes($my-app-theme); ``` Angular Material offers a `theme` mixin that emits styles for both color and typography and It’s the `all-component-themes` mixin. You can check the source file: [`src/material/core/theming/_all-theme.scss`](https://github.com/angular/components/blob/d336370565deb6a4db666783d484040e1fd99648/src/material/core/theming/_all-theme.scss#L42) to see the mixin `all-component-themes`: ```scss @mixin all-component-themes($theme) { $dedupe-key: 'angular-material-theme'; @include theming.private-check-duplicate-theme-styles($theme, $dedupe-key) { @include core-theme.theme($theme); @include card-theme.theme($theme); @include progress-bar-theme.theme($theme); @include tooltip-theme.theme($theme); @include form-field-theme.theme($theme); // other material components' themes... } } ``` Additionally, there is a `color` mixin that emits all components' color styles and a `typography` mixin that emits all components’ typography styles. They are `all-component-colors` and `all-component-typographies` mixins. These mixins emit styles for all 35+ components in Angular Material. This will produce unnecessary CSS, except when your application is using every single component from the library. Let’s look at the `styles` size after the `build` command and then I’ll show you how to reduce it: ![unoptimized styles bundle](https://res.cloudinary.com/dbgsyjnmu/image/upload/v1695718750/angular-material.dev/Screenshot_2023-09-26_140302_knexls.png "unoptimized styles bundle") ### Include only used components’ themes Just like `all-component-colors`, `all-component-typographies` and `all-component-themes`, each Angular Material component has a `color`, a `typography` and a `theme` mixin. For example, `MatButton` declares `button-color`, `button-typography`, and `button-density`. Each mixin emits only the styles corresponding to that area of customization. We can apply the styles for each of the components used in the application by including each of their theme SASS mixins. ```scss // @include mat.all-component-themes($my-app-theme); <-- removed @include mat.core-theme($my-app-theme); ``` `core-theme` emits theme-dependent styles for common features used across multiple components, like ripples. Next, we need to add component related styles. For this example, we will use [MatButton](https://material.angular.io/components/button/overview), so we will add `button-theme`: ```scss @include mat.button-theme($my-app-theme); ``` You can add other components’ theme’s in the same way. But, `core-theme` is only needed once per theme. Let’s look at the `styles` size now after build. ![optimized styles bundle](https://res.cloudinary.com/dbgsyjnmu/image/upload/v1695719910/angular-material.dev/Screenshot_2023-09-26_144757_cydbuv.png "optimized styles bundle") Notice how using only the needed components’ themes reduces the style's size. In our case, it was **67.23 kB** earlier and it’s reduced to **15.22 kB**, which is almost **77% less**. For better code management, we will move theme related code into `styles/themes/_all.scss`: ```scss // src/styles/themes/_all.scss @use "sass:map"; @use "@angular/material" as mat; $my-app-light-primary: mat.define-palette(mat.$indigo-palette); $my-app-light-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); $my-app-light-warn: mat.define-palette(mat.$red-palette); $my-app-light-theme: mat.define-light-theme( ( color: ( primary: $my-app-light-primary, accent: $my-app-light-accent, warn: $my-app-light-warn, ) ) ); ``` ## Apply custom theme in application Finally, make changes in `src/styles.scss`: ```scss // styles.scss @use "@angular/material" as mat; @use "./styles/themes/all" as themes; @include mat.core(); @include mat.core-theme(themes.$my-app-light-theme); @include mat.button-theme(themes.$my-app-light-theme); html, body { height: 100%; } body { margin: 0; font-family: Roboto, sans-serif; } ``` ## Output after creating custom theme Let’s add a `[mat-raised-button]` in application and see how it looks: ```html Raised Accent Warn ``` And the output should look like below: ![output after creating custom theme](https://res.cloudinary.com/dbgsyjnmu/image/upload/v1695741850/angular-material.dev/9ghL1oN_ojkoam.gif "output after creating custom theme") ## Using a pre-built theme When we installed Angular Material, we selected `Custom` in theme selection. If you want any pre-built theme, you can select any theme instead of `Custom`. There are 4 pre-built themes provided: | Theme | Light or dark? | Palettes (primary, accent, warn) | |--------------------------|--------------------|--------------------------------------| | deeppurple-amber.css | Light | deep-purple, amber, red | | indigo-pink.css | Light | indigo, pink, red | | pink-bluegray.css | Dark | pink, bluegray, red | | purple-green.css | Dark | purple, green, red | For instance, if you want to use `indigo-pink.css`’s theme, you just need to include that file in the styles array of your project’s `angular.json` file: ```json "styles": [ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", // other styles ], ``` These files include the CSS for every component in the library. To include only the CSS for a subset of components, you must use the Sass API detailed in [Defining a theme](/courses/md-ng/m2-ng-components/create-custom-theme#defining-a-theme) above.
Support Free Content Creation

Contributions & Support

Even though the courses and articles are available at no cost, your support in my endeavor to deliver top-notch educational content would be highly valued. Your decision to contribute aids me in persistently improving the course, creating additional resources, and maintaining the accessibility of these materials for all. I'm grateful for your consideration to contribute and make a meaningful difference!

Envelop
Don't miss any update

Stay up to date

Subscribe to the newsletter to stay up to date with articles, courses and much more!

Angular Material Dev

Angular Material Dev is one place stop for developers to learn about integrating Material Design in Angular applications like a pro.

Find us on X (Twitter) and LinkedIn