> Canonical URL: https://codingcat.dev/course/angularmaterial/lesson/angular-material-router-outlet

# Angular Material Router Outlet | Angular Material | CodingCat.dev Course

[🧶 Angular Material](/course/angularmaterial)Section 1.2 · Lesson 2 of 8[![](/logos/tags/angular-symbol-light.svg)![](/logos/tags/angular-symbol-dark.svg)Angular](/topic/angular)[![](/logos/firebase/firebase-symbol.png)![](/logos/firebase/firebase-symbol.png)Firebase](/topic/firebase)[![](/logos/tags/html-symbol-light.svg)![](/logos/tags/html-symbol-dark.svg)HTML](/topic/html)[![](/logos/tags/github-symbol-light.svg)![](/logos/tags/github-symbol-dark.svg)GitHub](/topic/github)[![](/logos/tags/css-symbol-light.svg)![](/logos/tags/css-symbol-dark.svg)CSS](/topic/css)[![](/logos/tags/nextjs-symbol-light.svg)![](/logos/tags/nextjs-symbol-dark.svg)Next.js](/topic/nextjs)[![](/logos/tags/typescript-symbol-light.svg)![](/logos/tags/typescript-symbol-dark.svg)TypeScript](/topic/typescript)[![](/logos/tags/git-symbol-light.svg)![](/logos/tags/git-symbol-dark.svg)Git](/topic/git)[← Prev Lesson](/course/angularmaterial/lesson/firebase-project-hosting)[Next Lesson →](/course/angularmaterial/lesson/firebase-authentication-and-authorization)

# Angular Material Router Outlet

![](https://cdn.sanity.io/media-libraries/mlttp0BZbCpV/images/6339543c6125be353037074c53064b8ec54e80d8-1920x1080.png?w=1920&h=1080&q=82&fit=max&auto=format)[@CodingCatDev62.5K / 100K Subscribers Goal](https://www.youtube.com/@codingcatdev?sub_confirmation=1)[Subscribe on YouTube→](https://www.youtube.com/@codingcatdev?sub_confirmation=1)[Watch on YouTube App ↗](https://www.youtube.com/watch?v=niJrSNQ1KwI&list=UUnKZ8gEb78zXKMi1ns-IQ2g)Lesson 2 / 8Course Lessons Outline▾1Section 1
- [1.1Firebase Project Hosting](/course/angularmaterial/lesson/firebase-project-hosting)
- [1.2Angular Material Router Outlet](/course/angularmaterial/lesson/angular-material-router-outlet)
- [1.3Firebase Authentication and Authorization](/course/angularmaterial/lesson/firebase-authentication-and-authorization)
- [1.4Angular Material Theming](/course/angularmaterial/lesson/angular-material-theming)
- [1.5Angular Material Dynamic Navigation using Firestore](/course/angularmaterial/lesson/angular-material-dynamic-navigation-using-firestore)
- [1.6Angular Material Forms from Firestore](/course/angularmaterial/lesson/angular-material-forms-from-firestore)
- [1.7Angular Material Reactive Forms Update Firestore](/course/angularmaterial/lesson/angular-material-reactive-forms-update-firestore)
- [1.8Angular Material Router Awareness](/course/angularmaterial/lesson/angular-material-router-awareness)

This lesson will start from a new Angular Project and walk through how to use Angular Material [Sidenav](https://material.angular.io/components/sidenav/overview) using the Angular [Router](https://angular.io/guide/router) with [Named Outlets](https://angular.io/guide/router#displaying-multiple-routes-in-named-outlets). This will be the begining of building a app for publishing book reviews.???? Demo: [https://ajonp-lesson-9.firebaseapp.com/](https://ajonp-lesson-9.firebaseapp.com/)

# Create Angular Project

If you have never used the [Angular CLI](https://cli.angular.io/) you will want to checkout the main page to get started.

Copied! 🐾

```
ng new angular-material-router-outlet
```

Please choose Yes for routing and SCSS.

## Add Material to Angular Project

> Make sure you have changed to the correct directory cd angular-material-router-outlet

We will now run an Angular schematic command, you can think of this as a workflow to help get your project up and running quicker. There are several schematics available and I would recommend reading [Angular Blog](https://blog.angular.io/schematics-an-introduction-dc1dfbc2a2b2) about schematics and [Angular Console](https://angularconsole.com/).

Copied! 🐾

```
ng add @angular/material
```

For the selections please choose custom, as we will add these in our next lesson.

## Open Project

Now you can open your new Angular project, if using VSCode

Copied! 🐾

```
cd angular-material-router-outlet && code .
```

You should see the base angular structure, including a routing module `app-routing.module.ts`

package.json

Copied! 🐾

```
{
  "name": "angular-material-router-outlet",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~7.1.0",
    "@angular/cdk": "~7.2.1",
    "@angular/common": "~7.1.0",
    "@angular/compiler": "~7.1.0",
    "@angular/core": "~7.1.0",
    "@angular/forms": "~7.1.0",
    "@angular/material": "^7.2.1",
    "@angular/platform-browser": "~7.1.0",
    "@angular/platform-browser-dynamic": "~7.1.0",
    "@angular/router": "~7.1.0",
    "core-js": "^2.5.4",
    "hammerjs": "^2.0.8",
    "rxjs": "~6.3.3",
    "tslib": "^1.9.0",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.11.0",
    "@angular/cli": "~7.1.3",
    "@angular/compiler-cli": "~7.1.0",
    "@angular/language-service": "~7.1.0",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.1.6"
  }
}
```

index.html

Copied! 🐾

```

    AngularMaterialRouterOutlet

- " rel="stylesheet" /> " rel="stylesheet" /> ``` # Serve Angular Project In order to preview this base setup you will need to run the angular serve command.Copied! 🐾 ``` ng serve ``` Now on [http://localhost:4200](http://localhost:4200/) you will see the default Angular page displayed. # Angular Modules In general a module is a way of packaging up several Angular based files that logically belong together. Direct from Angular's [docs](https://angular.io/guide/architecture-modules), "NgModules are containers for a cohesive block of code dedicated to an application domain, a workflow, or a closely related set of capabilities."We will use both [NgModule](https://angular.io/api/core/NgModule) and [Component](https://angular.io/api/core/Component) extensively through this lesson (and any Angular project).Many tutorials will have you start putting everything into app.component*, I like to keep the main app clean and load as much as possible after lazy loading. Creating a modules folder keeps things a little more concise, but do what you prefer most. # Angular Material Sidenav The Sidenav consists of three main html elements ``, ``, and ``. Visually these can be represented like ## Creating Sidenav Module To create a module we can leverage the Angular CLI and runCopied! 🐾 ``` ng g m modules/sidenav ``` Then we will need a component to display the Angular Material Sidenav.Copied! 🐾 ``` ng g c modules/sidenav ``` The output of these commands should give you this structure.You can then replace any contents in `app.component.html` withCopied! 🐾 ``` ``` Sidenav will be the main entrypoint for the entire application, so it will need to reside directly in app.component. If you are asking yourself where did `app-sidenav` come from, Great question! This is defined in `sidenav.component.ts` in the `@Component` decorator, in the property `selector: app-sidenav`. Now at this point `app.component.ts` still does not now how to find `sidenav.component.ts` so we must export it from `sidenav.module.ts` and import it into `app.module.ts`.sidenav.module.tsCopied! 🐾 ``` import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SidenavComponent } from './sidenav.component'; import { MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, MatListModule } from '@angular/material'; import { RouterModule } from '@angular/router'; @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule ], exports: [SidenavComponent] }) export class SidenavModule { } ``` app.module.tsCopied! 🐾 ``` import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { SidenavModule } from './modules/sidenav/sidenav.module'; import { OverlayContainer } from '@angular/cdk/overlay'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, AppRoutingModule, BrowserAnimationsModule, SidenavModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { constructor(overlayContainer: OverlayContainer) { overlayContainer.getContainerElement().classList.add('angular-material-router-app-theme'); } } ``` Now our app can find the Sidenav module and can use it to show any of the exported components. If you open the preview again [http://localhost:4200](http://localhost:4200/), you should now see "sidenav works!"I would recommend committing at this point.Copied! 🐾 ``` git add . && git commit -m "Initial sidenav" ``` ## Update sidenav.component Now that we know our component can be seen as plain text lets start using the Angular Material Sidenav component for styling our app. First we will need to tell `sidenav.module.ts` that we need to include this new component, by adding it to our imports from `@angular/material`.Copied! 🐾 ``` import { MatSidenavModule} from '@angular/material'; ... imports: [ CommonModule, MatSidenavModule, ... ``` Now we can will update sidenav.component.html to include the sidenav elements.Copied! 🐾 ``` drawer content ``` > If you were to preview the page now you will only see "content" as the drawer is automatically hidden. Update `mat-sidenav` element to have the drawer open and beside content.Copied! 🐾 ``` ... ``` Now you can preview again [http://localhost:4200](http://localhost:4200/). ## Add MatToolbar We can make our site look like most by adding a toolbar to the topCopied! 🐾 content " aria-label="Copy code" title="Copy code to clipboard"> ``` drawer menu content ``` Because we have added three new Angular Material elements `mat-toolbar`, `mat-icon-button` and `mat-icon` to our component, we will need to let `sidenav.component.ts` know where they are defined, so you need to import them in `sidenav.module.ts`.Copied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, ... ``` ## Add Angular Router Outlet The main content of our app needs a place to end up, this is what Angular's `router-outlet` accompishes. It is a placeholder that takes the markup from another component and places it on the page. For our app this will be the main outlet that other child outlets will nest under.Copied! 🐾 ``` ... ``` Also remember to add RouterModule to `sidenav.module` so that Angular understands the element ``.Copied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule], exports: [SidenavComponent] }) ``` This is a visual representation of what is happening in our code so far, mat-sidenav-content->router-outlet is where the reaminder of our app will live. # Lazy Loading Books Feature Module The first child route that we will setup is a book route. This will require us to create a new module and component. This time we will use an optional parameter `--routing` which will also create a routing module.Create Book ModulesCopied! 🐾 ``` ng g m modules/books --routing ``` Create Book ComponentCopied! 🐾 ``` ng g c modules/books ``` ## Update App routing We now need to configure the router so that the books feature module can be accessed. So we will go back to `app-routing.module.ts` and add a new route with path `books`. There is a special way to load modules in a lazy fashion, meaning they were not downloaded when first accessing the app but when first accessing the route. You can read more about Lazy Loading Modules in the [Angular Guide](https://angular.io/guide/lazy-loading-ngmodules).Copied! 🐾 ``` const routes: Routes = [ { path: 'books', loadChildren: './modules/books/books.module#BooksModule' } ]; ``` ## App Routing Default Route If someone enters the app without a specified path we need to redirect that request over to books so that content will show up correctly.Add to constant routes.Copied! 🐾 ``` { path: '', redirectTo: '/books', pathMatch: 'full' } ``` ## Update Books Feature Module Route Now that we have told the app router about a feature module we need to make sure that feature module knows which component it should load, so we will add an empty path.Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BooksComponent, } ] ``` You should now see in the live preview [http://localhost/books](http://localhost/books) a message that says "books works!". # Lazy Loading Welcome Feature Module Many sites will often have a welcome or home module that you will route your traffic to incase there are notifications, logins, or basic info requirements. So we will switch our base path over to this new feature module and leave books on a seperate path. This will be the same setup as our Books Module.Create Welcome ModulesCopied! 🐾 ``` ng g m modules/welcome --routing ``` Create Welcome ComponentCopied! 🐾 ``` ng g c modules/welcome ``` ## Update App routing Copied! 🐾 ``` const routes: Routes = [ { path: 'welcome', loadChildren: './modules/books/books.module#BooksModule' } ]; ``` ## App Routing Default Route Change this redirect from books to Welcome.app-routing.module.tsCopied! 🐾 ``` const routes: Routes = [ { path: "welcome", loadChildren: "./modules/welcome/welcome.module#WelcomeModule", }, { path: "books", loadChildren: "./modules/books/books.module#BooksModule" }, { path: "", redirectTo: "/welcome", pathMatch: "full" }, ]; ``` ## Update Welcome Feature Module Route welcome-routing.module.tsCopied! 🐾 ``` const routes: Routes = [ { path: '', component: WelcomeComponent, } ] ``` # Using Router Link for Navigation In order for us to navigate the site we need to add some navigational elements. Using an [Angular Material List](https://material.angular.io/components/list/overview#navigation-lists) with a specific `mat-nav-list` element type is just what we need for our sidenav drawer.Copied! 🐾 ``` ... #### Home #### Books ... ``` Don't forget that you will now need to add `RouterModule` and `MatListModule` in your `sidenav.module.ts` imports.sidenav.module.tsCopied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule ], ... ``` If you now preview [http://localhost:4200](http://localhost:4200/) you will see in the sidenav you can click on Home or Books and the content will change to "welcome works!" and books works!" respectively. ## Active Router Link You can style your link to know which link you are currently using by adding the attribute `routerLinkActive` and passing a class. We have already assigned ours to `active-link`.We can then add our style to `sidenav.component.scss` so that the active link changes to a bold blue.Copied! 🐾 ``` .active-link { color: blue; font-weight: bold !important; border: none; } ``` Because we have our home (welcome) route path assigned to '/' if you preview now both Books and Home would be highlighed. By changing our routerlink to `/welcome` this issue will be resolved. In later lessons we will also discuss routerLinkOptions such as `[routerLinkActiveOptions]="{exact:true}"`. # Toolbar Updates In our `mat-toolbar` we placed a button that currently calls a function that has not yet been defined. We need to assign a variable called snav by using `#snav` in the element `mat-sidenav`. ## Sidenav Toggle sidenav.component.htmlCopied! 🐾 ``` ``` We can then use this new variable and pass it on the button click output `(click)="snavToggle(snav)"`sidenav.component.htmlCopied! 🐾 ``` ``` ## Function for Toggle Using our new snav reference we can just call the method that exists on this object, it will open or close the sidenav drawer.sidenav.component.tsCopied! 🐾 ``` snavToggle(snav) { snav.toggle(); } ``` If you now preview [http://localhost:4200](http://localhost:4200/) you will see that the toolbar hamburger (three horizontal lines) button will open and close the sidenav drawer. ## Toolbar Title We can also specify a title to allow our home routerlink to return home.Copied! 🐾 ``` {{ title }} ``` sidenav.component.tsCopied! 🐾 ``` title = 'Lesson 9 - Angular Material Router Outlet'; ``` # Book Drawer as Named Outlet Now that we have our book feature module all setup with working navigation and toolbar, we are going to add a named outlet for a drawer on this page.Visually it will look like thisWe will change our `books.component.html` from having text to including an Angular Material Drawer (mat-drawer). Remember now we have `one` router-outlet in our `sidenav.component` and `two` router-outlets in `books.component`, one named for the drawer and one for content. ## Create Drawer Component No routing needed for this module as it will be used only inside of our books module and not as a feature module.moduleCopied! 🐾 ``` ng g m modules/books/book-drawer ``` componentCopied! 🐾 ``` ng g c modules/books/book-drawer ``` > Don't forget to export this component as it will be used in book-detail. book-drawer.module.tsCopied! 🐾 ``` ... @NgModule({ declarations: [BookDrawerComponent], imports: [ CommonModule ], exports: [ BookDrawerComponent ] ... ``` ## Add mat-drawer to Books There are three parts to the drawer just like sidenav, this is because they are the same with sidenav having a few additional structural features.Having attributes opened="true" will show the drawer on screen and having mode="side" will push the content to beside the drawer.modules/books/books.component.htmlCopied! 🐾 ``` ``` Remember to add MatSidenavModule to `books.module.ts`, or the `mat-drawer` element will not be recognized.Copied! 🐾 ``` @NgModule({ declarations: [BooksComponent], imports: [ CommonModule, BooksRoutingModule, MatSidenavModule ] }) ``` ## Create Book Detail Component We will use this as an additional child feature route of books, so we need the router module.moduleCopied! 🐾 ``` ng g m modules/books/book-detail --routing ``` componentCopied! 🐾 ``` ng g c modules/books/book-detail ``` ## Update Books Routing We no longer want just the BookComponent to load when the `/books` route is hit, we want it to load its children as well. We do this the same as we did with our `app-routing.module.ts` and we will lazy load it with `loadChildren`.Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BooksComponent, children: [ { path: '', loadChildren: './book-detail/book-detail.module#BookDetailModule' } ] } ]; ``` ## Update Book-Detail Routing with Named Outlet Now that the books module knows to lazy load the book-detail module on its base path we need to update the route in book-detail to load its own component. This however will have a special route with an `outlet` for the drawer as well, this tells the router that it must use only this named route for its [component.So](http://component.so/) the router will load: book-detail -> `` book-drawer -> ``Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BookDetailComponent }, { path: '', component: BookDrawerComponent, outlet: 'book-drawer' } ]; ``` If you now preview [http://localhost:4200/books](http://localhost:4200/books) you will see in a drawer "book-drawer works!" and in the content area "book-detail works!". # Final Thoughts The Angular Router is amazingly powerful, you can create sever nested routes, named routes, guarded routes...If you cloned the final GitHub repo you will see some additional style updates, I will be covering those in the next Angular Material Themeing lesson. # Angular Material Router Outlet This lesson will start from a new Angular Project and walk through how to use Angular Material [Sidenav](https://material.angular.io/components/sidenav/overview) using the Angular [Router](https://angular.io/guide/router) with [Named Outlets](https://angular.io/guide/router#displaying-multiple-routes-in-named-outlets). This will be the begining of building a app for publishing book reviews.???? Demo: [https://ajonp-lesson-9.firebaseapp.com/](https://ajonp-lesson-9.firebaseapp.com/) # Create Angular Project If you have never used the [Angular CLI](https://cli.angular.io/) you will want to checkout the main page to get started.Copied! 🐾 ``` ng new angular-material-router-outlet ``` Please choose Yes for routing and SCSS. ## Add Material to Angular Project > Make sure you have changed to the correct directory cd angular-material-router-outlet We will now run an Angular schematic command, you can think of this as a workflow to help get your project up and running quicker. There are several schematics available and I would recommend reading [Angular Blog](https://blog.angular.io/schematics-an-introduction-dc1dfbc2a2b2) about schematics and [Angular Console](https://angularconsole.com/).Copied! 🐾 ``` ng add @angular/material ``` For the selections please choose custom, as we will add these in our next lesson. ## Open Project Now you can open your new Angular project, if using VSCodeCopied! 🐾 ``` cd angular-material-router-outlet && code . ``` You should see the base angular structure, including a routing module `app-routing.module.ts`package.jsonCopied! 🐾 ``` { "name": "angular-material-router-outlet", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "private": true, "dependencies": { "@angular/animations": "~7.1.0", "@angular/cdk": "~7.2.1", "@angular/common": "~7.1.0", "@angular/compiler": "~7.1.0", "@angular/core": "~7.1.0", "@angular/forms": "~7.1.0", "@angular/material": "^7.2.1", "@angular/platform-browser": "~7.1.0", "@angular/platform-browser-dynamic": "~7.1.0", "@angular/router": "~7.1.0", "core-js": "^2.5.4", "hammerjs": "^2.0.8", "rxjs": "~6.3.3", "tslib": "^1.9.0", "zone.js": "~0.8.26" }, "devDependencies": { "@angular-devkit/build-angular": "~0.11.0", "@angular/cli": "~7.1.3", "@angular/compiler-cli": "~7.1.0", "@angular/language-service": "~7.1.0", "@types/node": "~8.9.4", "@types/jasmine": "~2.8.8", "@types/jasminewd2": "~2.0.3", "codelyzer": "~4.5.0", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~3.1.1", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~1.1.2", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.4.0", "ts-node": "~7.0.0", "tslint": "~5.11.0", "typescript": "~3.1.6" } } ``` index.htmlCopied! 🐾 ``` AngularMaterialRouterOutlet " rel="stylesheet" /> " rel="stylesheet" /> ``` # Serve Angular Project In order to preview this base setup you will need to run the angular serve command.Copied! 🐾 ``` ng serve ``` Now on [http://localhost:4200](http://localhost:4200/) you will see the default Angular page displayed. # Angular Modules In general a module is a way of packaging up several Angular based files that logically belong together. Direct from Angular's [docs](https://angular.io/guide/architecture-modules), "NgModules are containers for a cohesive block of code dedicated to an application domain, a workflow, or a closely related set of capabilities."We will use both [NgModule](https://angular.io/api/core/NgModule) and [Component](https://angular.io/api/core/Component) extensively through this lesson (and any Angular project).Many tutorials will have you start putting everything into app.component*, I like to keep the main app clean and load as much as possible after lazy loading. Creating a modules folder keeps things a little more concise, but do what you prefer most. # Angular Material Sidenav The Sidenav consists of three main html elements ``, ``, and ``. Visually these can be represented like ## Creating Sidenav Module To create a module we can leverage the Angular CLI and runCopied! 🐾 ``` ng g m modules/sidenav ``` Then we will need a component to display the Angular Material Sidenav.Copied! 🐾 ``` ng g c modules/sidenav ``` The output of these commands should give you this structure.You can then replace any contents in `app.component.html` withCopied! 🐾 ``` ``` Sidenav will be the main entrypoint for the entire application, so it will need to reside directly in app.component. If you are asking yourself where did `app-sidenav` come from, Great question! This is defined in `sidenav.component.ts` in the `@Component` decorator, in the property `selector: app-sidenav`. Now at this point `app.component.ts` still does not now how to find `sidenav.component.ts` so we must export it from `sidenav.module.ts` and import it into `app.module.ts`.sidenav.module.tsCopied! 🐾 ``` import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SidenavComponent } from './sidenav.component'; import { MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, MatListModule } from '@angular/material'; import { RouterModule } from '@angular/router'; @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule ], exports: [SidenavComponent] }) export class SidenavModule { } ``` app.module.tsCopied! 🐾 ``` import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { SidenavModule } from './modules/sidenav/sidenav.module'; import { OverlayContainer } from '@angular/cdk/overlay'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, AppRoutingModule, BrowserAnimationsModule, SidenavModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { constructor(overlayContainer: OverlayContainer) { overlayContainer.getContainerElement().classList.add('angular-material-router-app-theme'); } } ``` Now our app can find the Sidenav module and can use it to show any of the exported components. If you open the preview again [http://localhost:4200](http://localhost:4200/), you should now see "sidenav works!"I would recommend committing at this point.Copied! 🐾 ``` git add . && git commit -m "Initial sidenav" ``` ## Update sidenav.component* Now that we know our component can be seen as plain text lets start using the Angular Material Sidenav component for styling our app. First we will need to tell `sidenav.module.ts` that we need to include this new component, by adding it to our imports from `@angular/material`.Copied! 🐾 ``` import { MatSidenavModule} from '@angular/material'; ... imports: [ CommonModule, MatSidenavModule, ... ``` Now we can will update sidenav.component.html to include the sidenav elements.Copied! 🐾 ``` drawer content ``` > If you were to preview the page now you will only see "content" as the drawer is automatically hidden. Update `mat-sidenav` element to have the drawer open and beside content.Copied! 🐾 ``` ... ``` Now you can preview again [http://localhost:4200](http://localhost:4200/). ## Add MatToolbar We can make our site look like most by adding a toolbar to the topCopied! 🐾 content " aria-label="Copy code" title="Copy code to clipboard"> ``` drawer menu content ``` Because we have added three new Angular Material elements `mat-toolbar`, `mat-icon-button` and `mat-icon` to our component, we will need to let `sidenav.component.ts` know where they are defined, so you need to import them in `sidenav.module.ts`.Copied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, ... ``` ## Add Angular Router Outlet The main content of our app needs a place to end up, this is what Angular's `router-outlet` accompishes. It is a placeholder that takes the markup from another component and places it on the page. For our app this will be the main outlet that other child outlets will nest under.Copied! 🐾 ``` ... ``` Also remember to add RouterModule to `sidenav.module` so that Angular understands the element ``.Copied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule ], exports: [SidenavComponent] }) ``` This is a visual representation of what is happening in our code so far, mat-sidenav-content->router-outlet is where the reaminder of our app will live. # Lazy Loading Books Feature Module The first child route that we will setup is a book route. This will require us to create a new module and component. This time we will use an optional parameter `--routing` which will also create a routing module.Create Book ModulesCopied! 🐾 ``` ng g m modules/books --routing ``` Create Book ComponentCopied! 🐾 ``` ng g c modules/books ``` ## Update App routing We now need to configure the router so that the books feature module can be accessed. So we will go back to `app-routing.module.ts` and add a new route with path `books`. There is a special way to load modules in a lazy fashion, meaning they were not downloaded when first accessing the app but when first accessing the route. You can read more about Lazy Loading Modules in the [Angular Guide](https://angular.io/guide/lazy-loading-ngmodules).Copied! 🐾 ``` const routes: Routes = [ { path: 'books', loadChildren: './modules/books/books.module#BooksModule' } ]; ``` ## App Routing Default Route If someone enters the app without a specified path we need to redirect that request over to books so that content will show up correctly.Add to constant routes.Copied! 🐾 ``` { path: '', redirectTo: '/books', pathMatch: 'full' } ``` ## Update Books Feature Module Route Now that we have told the app router about a feature module we need to make sure that feature module knows which component it should load, so we will add an empty path.Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BooksComponent, } ] ``` You should now see in the live preview [http://localhost/books](http://localhost/books) a message that says "books works!". # Lazy Loading Welcome Feature Module Many sites will often have a welcome or home module that you will route your traffic to incase there are notifications, logins, or basic info requirements. So we will switch our base path over to this new feature module and leave books on a seperate path. This will be the same setup as our Books Module.Create Welcome ModulesCopied! 🐾 ``` ng g m modules/welcome --routing ``` Create Welcome ComponentCopied! 🐾 ``` ng g c modules/welcome ``` ## Update App routing Copied! 🐾 ``` const routes: Routes = [ { path: 'welcome', loadChildren: './modules/books/books.module#BooksModule' } ]; ``` ## App Routing Default Route Change this redirect from books to Welcome.app-routing.module.tsCopied! 🐾 ``` const routes: Routes = [ { path: 'welcome', loadChildren: './modules/welcome/welcome.module#WelcomeModule' }, { path: 'books', loadChildren: './modules/books/books.module#BooksModule' }, { path: '', redirectTo: '/welcome', pathMatch: 'full' } ]; ``` ## Update Welcome Feature Module Route welcome-routing.module.tsCopied! 🐾 ``` const routes: Routes = [ { path: '', component: WelcomeComponent, } ] ``` # Using Router Link for Navigation In order for us to navigate the site we need to add some navigational elements. Using an [Angular Material List](https://material.angular.io/components/list/overview#navigation-lists) with a specific `mat-nav-list` element type is just what we need for our sidenav drawer.Copied! 🐾 ``` ... #### Home #### Books ... ``` Don't forget that you will now need to add `RouterModule` and `MatListModule` in your `sidenav.module.ts` imports.sidenav.module.tsCopied! 🐾 ``` @NgModule({ declarations: [SidenavComponent], imports: [ CommonModule, MatSidenavModule, MatToolbarModule, MatIconModule, MatButtonModule, RouterModule, MatListModule ], ... ``` If you now preview [http://localhost:4200](http://localhost:4200/) you will see in the sidenav you can click on Home or Books and the content will change to "welcome works!" and books works!" respectively. ## Active Router Link You can style your link to know which link you are currently using by adding the attribute `routerLinkActive` and passing a class. We have already assigned ours to `active-link`.We can then add our style to `sidenav.component.scss` so that the active link changes to a bold blue.Copied! 🐾 ``` .active-link { color: blue; font-weight: bold !important; border: none; } ``` Because we have our home (welcome) route path assigned to '/' if you preview now both Books and Home would be highlighed. By changing our routerlink to `/welcome` this issue will be resolved. In later lessons we will also discuss routerLinkOptions such as `[routerLinkActiveOptions]="{exact:true}"`. # Toolbar Updates In our `mat-toolbar` we placed a button that currently calls a function that has not yet been defined. We need to assign a variable called snav by using `#snav` in the element `mat-sidenav`. ## Sidenav Toggle sidenav.component.htmlCopied! 🐾 ``` ``` We can then use this new variable and pass it on the button click output `(click)="snavToggle(snav)"`sidenav.component.htmlCopied! 🐾 ``` ``` ## Function for Toggle Using our new snav reference we can just call the method that exists on this object, it will open or close the sidenav drawer.sidenav.component.tsCopied! 🐾 ``` snavToggle(snav) { snav.toggle(); } ``` If you now preview [http://localhost:4200](http://localhost:4200/) you will see that the toolbar hamburger (three horizontal lines) button will open and close the sidenav drawer. ## Toolbar Title We can also specify a title to allow our home routerlink to return home.Copied! 🐾 ``` {{ title }} ``` sidenav.component.tsCopied! 🐾 ``` title = 'Lesson 9 - Angular Material Router Outlet'; ``` # Book Drawer as Named Outlet Now that we have our book feature module all setup with working navigation and toolbar, we are going to add a named outlet for a drawer on this page.Visually it will look like thisWe will change our `books.component.html` from having text to including an Angular Material Drawer (mat-drawer). Remember now we have `one` router-outlet in our `sidenav.component` and `two` router-outlets in `books.component`, one named for the drawer and one for content. ## Create Drawer Component No routing needed for this module as it will be used only inside of our books module and not as a feature module.moduleCopied! 🐾 ``` ng g m modules/books/book-drawer ``` componentCopied! 🐾 ``` ng g c modules/books/book-drawer ``` > Don't forget to export this component as it will be used in book-detail. book-drawer.module.tsCopied! 🐾 ``` ... @NgModule({ declarations: [BookDrawerComponent], imports: [ CommonModule ], exports: [ BookDrawerComponent ] ... ``` ## Add mat-drawer to Books There are three parts to the drawer just like sidenav, this is because they are the same with sidenav having a few additional structural features.Having attributes opened="true" will show the drawer on screen and having mode="side" will push the content to beside the drawer.modules/books/books.component.htmlCopied! 🐾 ``` ``` Remember to add MatSidenavModule to `books.module.ts`, or the `mat-drawer` element will not be recognized.Copied! 🐾 ``` @NgModule({ declarations: [BooksComponent], imports: [ CommonModule, BooksRoutingModule, MatSidenavModule ] }) ``` ## Create Book Detail Component We will use this as an additional child feature route of books, so we need the router module.moduleCopied! 🐾 ``` ng g m modules/books/book-detail --routing ``` componentCopied! 🐾 ``` ng g c modules/books/book-detail ``` ## Update Books Routing We no longer want just the BookComponent to load when the `/books` route is hit, we want it to load its children as well. We do this the same as we did with our `app-routing.module.ts` and we will lazy load it with `loadChildren`.Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BooksComponent, children: [ { path: '', loadChildren: './book-detail/book-detail.module#BookDetailModule' } ] } ]; ``` ## Update Book-Detail Routing with Named Outlet Now that the books module knows to lazy load the book-detail module on its base path we need to update the route in book-detail to load its own component. This however will have a special route with an `outlet` for the drawer as well, this tells the router that it must use only this named route for its [component.So](http://component.so/) the router will load: book-detail -> `` book-drawer -> ``Copied! 🐾 ``` const routes: Routes = [ { path: '', component: BookDetailComponent }, { path: '', component: BookDrawerComponent, outlet: 'book-drawer' } ]; ``` If you now preview [http://localhost:4200/books](http://localhost:4200/books) you will see in a drawer "book-drawer works!" and in the content area "book-detail works!". # Final Thoughts The Angular Router is amazingly powerful, you can create sever nested routes, named routes, guarded routes...If you cloned the final GitHub repo you will see some additional style updates, I will be covering those in the next Angular Material Themeing lesson.✏️ Visual Architecture Diagram ## how this course connects together. Follow AJ through the layered stack topology from input contract to production output.Let’s build it!✏️ Architecture Diagram: Angular Material: Angular Material Router OutletLAYERED SYSTEM STACKARCHITECTURE DIAGRAM[Diagram Walkthrough]Content-driven layered-stack diagram for Angular Material: Angular Material Router Outlet: Section 1 -> Angular Material -> Verified Production Artifact.AAA Contrast Verified ## related deep dives. [View All&rarr;](/blog)[![Sanity Knowledge Bases](https://cdn.sanity.io/media-libraries/mlttp0BZbCpV/images/38b0f021c51d97043c8a1ebf31d505a0ea877b7c-2752x1536.jpg?w=1920&q=82&fit=max&auto=format)](/post/sanity-knowledge-bases)October 17, 2026[![](/logos/tags/mcp-symbol-light.svg)![](/logos/tags/mcp-symbol-dark.svg)MCP](/topic/mcp)[#AI & Agents](/topic/ai)[![](/logos/sanity/Sanity-Symbol--black_on_transparent.svg)![](/logos/sanity/Sanity-Symbol--white_on_transparent.svg)Sanity](/topic/sanity)[+5](/post/sanity-knowledge-bases) ### [Sanity Knowledge Bases](/post/sanity-knowledge-bases) Eliminate query-time guessing in your AI agents. Learn how Sanity Context Knowledge Bases compile structured datasets, crawled documentation websites, and uploaded files ahead of time, resolve conflicting facts, and serve a compact outline over Context MCP.[![Alex Patterson](https://cdn.sanity.io/media-libraries/mlttp0BZbCpV/images/a606dfaa381aab08ddbe16a33fe1d3e1fb37c927-400x400.jpg?w=96&h=96&q=82&fit=max&auto=format)Alex Patterson](/author/alex-patterson)[![The Odin Project 5: Advanced HTML, CSS View Transitions & WCAG Accessibility](https://cdn.sanity.io/images/hfh83o0w/production/93736ccee5b8c088a202f319ce1223899a41f6bf-1376x768.png?w=1376&q=82&fit=max&auto=format)](/course/odin-advanced-html-css-and-a11y)November 4, 2026[![](/logos/tags/css-symbol-light.svg)![](/logos/tags/css-symbol-dark.svg)CSS](/topic/css)[#Accessibility](/topic/a11y)[![](/logos/tags/html-symbol-light.svg)![](/logos/tags/html-symbol-dark.svg)HTML](/topic/html)[+1](/course/odin-advanced-html-css-and-a11y) ### [The Odin Project 5: Advanced HTML, CSS View Transitions & WCAG Accessibility](/course/odin-advanced-html-css-and-a11y) Build 60fps GPU-accelerated animations, multi-page Astro View Transitions, WCAG AAA focus rings, and accessible native <dialog> and Popover components.[![Alex Patterson](https://cdn.sanity.io/media-libraries/mlttp0BZbCpV/images/a606dfaa381aab08ddbe16a33fe1d3e1fb37c927-400x400.jpg?w=96&h=96&q=82&fit=max&auto=format)Alex Patterson](/author/alex-patterson)[Course Outline](/course/angularmaterial) ## Angular Material 2/81 ### Section 1 [1.1Firebase Project Hosting](/course/angularmaterial/lesson/firebase-project-hosting)
- [1.2Angular Material Router Outlet▶](/course/angularmaterial/lesson/angular-material-router-outlet)
- [1.3Firebase Authentication and Authorization](/course/angularmaterial/lesson/firebase-authentication-and-authorization)
- [1.4Angular Material Theming](/course/angularmaterial/lesson/angular-material-theming)
- [1.5Angular Material Dynamic Navigation using Firestore](/course/angularmaterial/lesson/angular-material-dynamic-navigation-using-firestore)
- [1.6Angular Material Forms from Firestore](/course/angularmaterial/lesson/angular-material-forms-from-firestore)
- [1.7Angular Material Reactive Forms Update Firestore](/course/angularmaterial/lesson/angular-material-reactive-forms-update-firestore)
- [1.8Angular Material Router Awareness](/course/angularmaterial/lesson/angular-material-router-awareness)

@CodingCatDev on YouTube62.5K / 100K

Subscribe for new course lessons and architecture deep dives every week.

[Subscribe for New Lessons →](https://www.youtube.com/@codingcatdev?sub_confirmation=1)