Exploring Material 3 Design With Angular Material

shhdharmen

Dharmen Shah

Posted on April 26, 2024

Exploring Material 3 Design With Angular Material

Angular Material team is soon going to roll out the stable usage of it's Material 3 (M3) integration. This integration is already part of it's next major release.

In this article, we are going to use the yet to be released 18 (or next) version of Angular, Angular CLI and Angular Material. The goal of this article is to give a quick idea about what is coming up with Angular Material in it's next major release.

Creating a v18 Angular Project

npx @angular/cli@next new angular-material-3
Enter fullscreen mode Exit fullscreen mode

Then select Sass (SCSS) for styling and No for SSR/SSG/Prerendering.

? Which stylesheet format would you like to use? Sass (SCSS)     [ https://sass-lang.com/documentation/syntax#scss ]
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
Enter fullscreen mode Exit fullscreen mode

And lastly, move into the project folder:

cd angular-material-3
Enter fullscreen mode Exit fullscreen mode

Adding Angular Material v18

Let's add @angular/material into the newly created project:

ng add @angular/material@next
Enter fullscreen mode Exit fullscreen mode

And select answers as below:

? Choose a prebuilt theme name, or "custom" for a custom theme: Custom
? Set up global Angular Material typography styles? Yes
? Include the Angular animations module? Include and enable animations
Enter fullscreen mode Exit fullscreen mode

New M3 Themes

When selecting the theme, notice that now we are getting options of new themes:

Theme Name
Rose & Red
Azure & Blue
Magenta & Violet
Cyan & Orange

These are new themes created by Angular Material team to be compatible to M3.

If you have selected Custom, your styles.scss would look like below:

@use "@angular/material" as mat;

@include mat.core();

$angular-material-3-theme: mat.define-theme(
  (
    color: (
      theme-type: light,
      primary: mat.$azure-palette,
      tertiary: mat.$blue-palette,
    ),
    density: (
      scale: 0,
    ),
  )
);

:root {
  @include mat.all-component-themes($angular-material-3-theme);
}
Enter fullscreen mode Exit fullscreen mode

The syntax is almost similar to what it was in Material 2 (M2) integration with Angular Material. But, notice the usage of new palettes. We are using $azure-palette and $blue-palette. Below are all new palettes introduced in M3 integration with Angular Material, that can be used with the primary and tertiary options:

  • $red-palette
  • $green-palette
  • $blue-palette
  • $yellow-palette
  • $cyan-palette
  • $magenta-palette
  • $orange-palette
  • $chartreuse-palette
  • $azure-palette
  • $violet-palette
  • $rose-palette

Creating basic app

Let's create a simple application to see and understand basic usages of updated SASS mixins for M3 in Angular Material.

We are going to use Angular Material Schematics to generate components:

ng generate @angular/material:navigation layout
ng generate @angular/material:dashboard dashboard
ng generate @angular/material:address-form address-form
ng generate @angular/material:table table
ng generate @angular/material:tree tree
ng generate @angular/material:drag-drop drag-drop
Enter fullscreen mode Exit fullscreen mode

Updating layout

Go to src/app/layout/layout.component.html and add <ng-content> in <mat-sidenav-content> like below:

<mat-sidenav-content>

    <!--mat-toolbar remains same-->

    <div class="sidenav-scroll-wrapper">
      <div class="sidenav-content">
        <ng-content></ng-content>
      </div>
    </div>
  </mat-sidenav-content>
Enter fullscreen mode Exit fullscreen mode

Next, let's add and modify some styling in src/app/layout/layout.component.scss so that sidenav content looks more M3 oriented:

.sidenav-container {
  height: 100%;
}

.sidenav {
  width: 240px;
  padding: 0 8px;
  box-sizing: border-box;
}

.mat-toolbar.mat-primary {
  position: sticky;
  top: 0;
  z-index: 1;
}

mat-sidenav-content {
  padding-right: 16px;
}

.sidenav-scroll-wrapper {
  height: calc(100dvh - 64px - 16px);
  overflow: auto;
  border-radius: 16px;
  box-sizing: border-box;
}

.sidenav-content {
  max-height: 100%;
  overflow-y: auto;
  padding: 16px;
  box-sizing: border-box;
  @media (pointer: fine) {
    &::-webkit-scrollbar {
      background-color: transparent;
      width: 8px;
    }
    &::-webkit-scrollbar-thumb {
      border-radius: 4px;
    }
  }
}

@media (max-width: 959.98px) {
  mat-sidenav-content {
    padding-right: 8px;
    padding-left: 8px;
  }
  .sidenav-scroll-wrapper {
    height: calc(100dvh - 64px);
  }
  .sidenav-content {
    overflow-y: visible;
    padding: 8px;
  }
}

Enter fullscreen mode Exit fullscreen mode

Using layout

Now, simply go to src/app/app.component.html and update it's content with below:

<app-layout>
  <router-outlet />
</app-layout>
Enter fullscreen mode Exit fullscreen mode

Also, don't forget to import LayoutComponent in src/app/app.component.ts.

At this point, the output looks like below:

output after updating layout

Let's add some colors in the content area so that it's easy to distinguish.

Theming layout

Create a file src/app/layout/_layout-component.theme.scss with below content:

@use "@angular/material" as mat;

@mixin theme($theme) {
  .sidenav-scroll-wrapper {
    background-color: rgba(mat.get-theme-color($theme, primary-container), 0.75);
  }
  .sidenav-content {
    @media (pointer: fine) {
      &::-webkit-scrollbar-thumb {
        background-color: mat.get-theme-color($theme, primary);
      }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Notice the usages of get-theme-color mixin:

  1. To get color of the primary-container role, we used mat.get-theme-color($theme, primary-container)
  2. To get color from tonal palette, we used mat.get-theme-color($theme, primary).

To learn more, checkout Reading tonal palette colors and Reading color roles.

Using layout component theme

Now, include and call this mixin in main styles.scss file:

@use "./app/layout/layout-component.theme";

:root {
    @include layout-component.theme($theme);
}
Enter fullscreen mode Exit fullscreen mode

Let's see the output now:

output after layout theming

Updating routes

Go to your src/app/app.routes.ts and update the routes:

import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'dashboard',
  },
  {
    path: 'dashboard',
    loadComponent: () =>
      import('./dashboard/dashboard.component').then(
        (c) => c.DashboardComponent
      ),
      title: 'Dashboard'
  },
  {
    path: 'address',
    loadComponent: () =>
      import('./address-form/address-form.component').then(
        (c) => c.AddressFormComponent
      ),
      title: 'Address'
  },
  {
    path: 'table',
    loadComponent: () =>
      import('./table/table.component').then(
        (c) => c.TableComponent
      ),
      title: 'Table'
  },
  {
    path: 'tree',
    loadComponent: () =>
      import('./tree/tree.component').then(
        (c) => c.TreeComponent
      ),
      title: 'Tree'
  },
  {
    path: 'drag-drop',
    loadComponent: () =>
      import('./drag-drop/drag-drop.component').then(
        (c) => c.DragDropComponent
      ),
      title: 'Drag-Drop'
  },
];

Enter fullscreen mode Exit fullscreen mode

And to load the routes, we will first update src/app/layout/layout.component.ts:

import { RouterLink, RouterLinkActive } from '@angular/router';

@Component({
  selector: 'app-layout',
  // rest remains same
  imports: [
    // Add below imports
    RouterLink,
    RouterLinkActive
  ]
})
export class LayoutComponent {
  rootRoutes = routes.filter(r=>r.path);

  // rest remains same
}
Enter fullscreen mode Exit fullscreen mode

Now, replace <mat-nav-list> content with below:

<mat-nav-list>
    @for (item of rootRoutes; track $index) {
        <a
            mat-list-item
            [routerLink]="item.path"
            #link="routerLinkActive"
            routerLinkActive
            [activated]="link.isActive"
        >
            {{ item.title }}
        </a>
    }
</mat-nav-list>
Enter fullscreen mode Exit fullscreen mode

At this point the output looks like below:

Custom M3 theme

We saw in the beginning that Angular Material team provides some pre-built palettes and themes.

But, it is also possible to generate a theme based on a custom color. To do so, simply run below command:

ng generate @angular/material:m3-theme
Enter fullscreen mode Exit fullscreen mode

After running the above script, your will be presented with below question:

What HEX color should be used to generate the M3 theme? It will represent your primary color palette. (ex. #ffffff)
Enter fullscreen mode Exit fullscreen mode

Simply enter #6750A4 for the above question and leave blank for the rest of the questions.

The schematic will create a file called m3-theme.scss at root. You can explore the file to understand how the theme is created:

// m3-theme.scss - content reduced for brevity

$light-theme: mat.define-theme((
  color: (
    theme-type: light,
    primary: $_primary,
    tertiary: $_tertiary,
  )
));
$dark-theme: mat.define-theme((
  color: (
    theme-type: dark,
    primary: $_primary,
    tertiary: $_tertiary,
  )
));
Enter fullscreen mode Exit fullscreen mode

Now, you can simply use these newly created themes in main styles.scss:

@use "../m3-theme";

:root {
  @include mat.all-component-themes(m3-theme.$light-theme);
}
Enter fullscreen mode Exit fullscreen mode

And the output will look like below:

embedded video

Conclusion

We created a v18 Angular application. And installed @angular/material's next (v18) version in it.

Then we created some boilerplate components like dashboard, address-form, tree, table and drag-drop views using Angular Material Schematics.

After creating components, we modified layout component and it's styling, and we started using it in main app component.

Lastly, we learned the usage of new schematic ng generate @angular/material:m3-theme.

The code is available on GitHub.

Live Playground

💖 💪 🙅 🚩
shhdharmen
Dharmen Shah

Posted on April 26, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related