This article has been updated to the latest version of Angular 6. Some content may still be applicable to Angular 2 or other previous versions.

Adding animations can create an excellent user experience when applied appropriately in an application. In this short tutorial, we will show how to use Angular’s Animation API to create a simple fade in and fade out effect when we route between components.

Set up Routes

First, we need to set up some routes in our application. In this simple app, we will set a home and about route.



import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}


Now that we have our routes set up lets set up our application template.



<header>
  <nav>
    <a routerLink="">home</a>
    <a routerLink="about">about</a>
  </nav>
</header>

<main>
  <router-outlet></router-outlet>
</main>


For now, this will get our routing working but won’t have our fade in and fade out animation just yet.

Creating an Animation

First we need to add the Angular Animation module to our application.



import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

@NgModule({
  imports: [BrowserModule, BrowserAnimationsModule, AppRoutingModule],
  declarations: [AppComponent, HomeComponent, AboutComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }


We will now add a new file animations.ts. In this file, we will define our fade animation.



import {
  trigger,
  animate,
  transition,
  style,
  query
} from '@angular/animations';

export const fadeAnimation = trigger('fadeAnimation', [
  // The '* => *' will trigger the animation to change between any two states
  transition('* => *', [
    // The query function has three params.
    // First is the event, so this will apply on entering or when the element is added to the DOM.
    // Second is a list of styles or animations to apply.
    // Third we add a config object with optional set to true, this is to signal
    // angular that the animation may not apply as it may or may not be in the DOM.
    query(
      ':enter',
      [style({ opacity: 0 })],
      { optional: true }
    ),
    query(
      ':leave',
      // here we apply a style and use the animate function to apply the style over 0.3 seconds
      [style({ opacity: 1 }), animate('0.3s', style({ opacity: 0 }))],
      { optional: true }
    ),
    query(
      ':enter',
      [style({ opacity: 0 }), animate('0.3s', style({ opacity: 1 }))],
      { optional: true }
    )
  ])
]);


Now that we have defined our animation we need to explicitly set what element it should be applied to. So let’s go back to our application component template.



<header>
  <nav>
    <a routerLink="">home</a>
    <a routerLink="about">about</a>
  </nav>
</header>

<main [@fadeAnimation]="o.isActivated ? o.activatedRoute : ''">
  <router-outlet #o="outlet"></router-outlet>
</main>


On the router outlet, we create a template reference to the outlet directive with the template variable assignment #o="outlet". With this reference to the outlet directive, we can get the information of when the router outlet is active to trigger our fade animation.

Next in our App Component TypeScript file we need to add some information to our component decorator.



import { Component } from '@angular/core';
import { fadeAnimation } from './animations';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [fadeAnimation] // register the animation
})
export class AppComponent { }


The last missing piece is some CSS in our global style sheet.



router-outlet ~ * {
  position: absolute;
  height: 100%;
  width: 100%;
}


This selector will select the component that is inserted into the DOM and ensure it fills in the space of its parent element so the animation correctly applies.

To see a full working example check out the demo link below!

Become a Patron View Code Demo