Angular Animations Example

By Arvind Rai, February 13, 2024
This page will walk through Angular animations example. Angular animation integrates CSS animations. Angular animations are built on top of standard W3C web animation API and run natively on browsers that support it. Animations are created using functions such as animate, state, style, transition, trigger, sequence, group, keyframes etc. Animation trigger name is bound to element of the template of component or host element of child component to animate it. Animation takes place for a given duration with given easing function.
In Angular, we define states of element for animation and when we move from one state to another state, animation takes place. We can create a sequence and group of animation functions. The sequence of animation function executes sequentially and group of animation functions executes in parallel. Animation state of an element is defined using CSS properties and if the element is not available in DOM then that state is called void. Any state that has not been defined in our animation trigger function then that state is called as * which is default state.
On this page we will discuss configuration steps to integrate animation with our application and then we will provide examples for different animation functions.

Project Structure

Find the project structure of our demo application.
angular-demo
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--animations
|   |   |    |
|   |   |    |--on-off-1.animation.ts
|   |   |    |--on-off-2.animation.ts
|   |   |    |--on-off-3.animation.ts
|   |   |    |--on-off-4.animation.ts
|   |   |    |--round-anticlock.animation.ts
|   |   |    |--fly-in-out.animation.ts
|   |   | 
|   |   |--book.ts
|   |   |--book.service.ts
|   |   |--book.component.ts
|   |   |--book.component.html
|   |   |--addbook.component.ts
|   |   |--addbook.component.html
|   |   |--book-detail.component.ts
|   |   |--book-detail.component.html
|   |   |--app.component.ts
|   |   |--app-routing.module.ts
|   |   |--app.module.ts 
|   | 
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json 

Configure Animation in Angular Application

Find the steps to configure animation in our Angular application.
Step-1: Make sure that package.json contains @angular/animations in dependencies block. If not available then either upgrade Angular CLI or configure @angular/animations in dependencies block and run npm install .
Step-2: Configure BrowserAnimationsModule in application module to support animations.
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  imports: [     
        ---
	BrowserAnimationsModule
  ]
  ---
})
export class AppModule { } 
Step-3: Find a sample animation code.
on-off.animation.ts
import { animate, state, style, transition, trigger } from '@angular/animations';

export const ON_OFF_ANIMATION =
	trigger('onOffTrigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  transform: 'scale(1.1)'
		})),
		transition('off => on', animate('.6s 100ms ease-in')),
		transition('on => off', animate('.7s 100ms ease-out'))
	]); 
In the above animation code onOffTrigger is trigger name.
Step-4: To use animation in component, the decorator @Component provides a metadata named as animations.
import { Component } from '@angular/core';
import { ON_OFF_ANIMATION } from './animations/on-off.animation';

@Component({
  ---
  animations: [ ON_OFF_ANIMATION ]
})
export class BookComponent {}
Using animations metadata we can write animation code inline or provide the constant that is assigned with animation code. Inline animation code within component can be written as follows.
import { Component } from '@angular/core';

@Component({
  ---
 animations: [ trigger('onOffTrigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  transform: 'scale(1.1)'
		})),
		transition('off => on', animate('.6s 100ms ease-in')),
		transition('on => off', animate('.7s 100ms ease-out'))
	])]
})
export class BookComponent {} 
In the above animation code onOffTrigger is trigger name.
Step-5: To use animation in our HTML template we need to bind trigger name using property binding. Suppose we have an animation trigger with name onOffTrigger then it will be bound to HTML element using @ as [@onOffTrigger] = "trigger_state_name".
<div [@onOffTrigger] = "trigger_state_name "> 
  ---
</div> 
In the sample animation code we have two trigger state off and on that will be assigned to [@onOffTrigger] at run time.

Create Service and Component for Demo

Find a service and component that we will use in our demo.
book.service.ts
import { Injectable } from '@angular/core';
import { Book } from './book';

const BOOKS: Book[] = [
	{"id": 1, "name": "Java", "author": "Mahesh", "state": "off"},
	{"id": 2, "name": "Angular", "author": "Mahesh", "state": "off"},
	{"id": 3, "name": "Spring", "author": "Krishna", "state": "off"},
	{"id": 4, "name": "Hibernate", "author": "Krishna", "state": "off"}
];
let booksPromise = Promise.resolve(BOOKS);

@Injectable()
export class BookService { 
    getBooks(): Promise<Book[]> {
	   return booksPromise;
    }
    addBook(book: Book): Promise<Book> {
	  return this.getBooks()
	   .then(books => {
	       let maxIndex = books.length - 1;
	       let bookWithMaxIndex = books[maxIndex];
	       book.id = bookWithMaxIndex.id + 1;
	       book.state= 'off';
	       books.push(book);
	       return book;
	     }
	    );
    }	
} 
book.ts
export interface Book {
  id: number;
  name: string;
  author: string;
  state: string;
} 
book.component.ts
import { Component, OnInit } from '@angular/core';

import { BookService } from './book.service';
import { Book } from './book';
import { ON_OFF_1_ANIMATION }   from './animations/on-off-1.animation';
import { ON_OFF_2_ANIMATION }   from './animations/on-off-2.animation';
import { ON_OFF_3_ANIMATION }   from './animations/on-off-3.animation';
import { ON_OFF_4_ANIMATION }   from './animations/on-off-4.animation';

@Component({
  templateUrl: 'book.component.html',
  animations: [ 
          ON_OFF_1_ANIMATION,
	  ON_OFF_2_ANIMATION,
	  ON_OFF_3_ANIMATION,
	  ON_OFF_4_ANIMATION,
  ]
})
export class BookComponent implements OnInit {
  books = {} as Promise<Book[]>;
  constructor(private bookService: BookService) {
  }
  ngOnInit() {
     this.books = this.bookService.getBooks();
  }
  toggle(book: Book) {
     book.state =  (book.state === 'on') ? 'off' : 'on'; 
  }
}
book.component.html
<h3>Click and then Click to test Animation</h3>
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff1Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul>
<br/>
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff2Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul>
<br/>
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff3Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul>
<br/>
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff4Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul> 
Find the output.
Angular Animations Example

trigger

trigger is an animation-specific function that creates a trigger with state and transition entries. trigger function accepts following arguments.
1. Trigger name
2. Array of state and transition.

Trigger is used as follows.
trigger("onOffTrigger", [
   state(...),
   state(...),
   transition(...),
   transition(...)
]) 
Trigger function can have any number of state and transition entries.

style

style is an animation-specific function. It is defined with key/value of CSS properties. style function is passed as an argument in animation-specific functions such as state, transition, animate and keyframes. Animation style function is defined as follows.
style({
  backgroundColor: '#E5E7E9',
  color: '#1C2833',
  fontSize: '18px',		  
  transform: 'scale(1)'
}) 

state

state is an animation-specific function. It is an animation state within the given trigger. state function accepts following arguments.
1. State name
2. style

Find the example.
on-off-1.animation.ts
import { animate, state, style, transition, trigger } from '@angular/animations';

export const ON_OFF_1_ANIMATION =
	trigger('onOff1Trigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  color: '#1C2833',
		  fontSize: '18px',		  
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  color: '#F0F3F4',
		  fontSize: '22px',
		  transform: 'scale(1.1)'
		}))
	]); 
Find the example to bind the trigger onOff1Trigger in our HTML template.
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff1Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul> 
When the book.state value is off then the animation state with name off will be applied and when the book.state value is on then the animation state with name on will be applied.
State can also be void and * in animation.

void : This state is reserved by Angular. void state means element is not the part of application anymore. void state example is that when ngIf expression value is false and that element is no more in DOM.

* : This is the default state. This is a state which has not been declared within the trigger function. * state is used for dynamic start and ending state in animation.

animate

animate is an animation-specific function. It specifies an animation step. We need to pass following arguments to animate function.
1. Timing expression
2. style or keyframes function. This argument is optional.

Timing expression is the combination of duration, delay and easing. They are written in following formats.

Timing expression: 'duration delay easing'
Find the explanation.
duration: It defines how long animation will take place. It can be a plane number or string. If we write plane number then by default the time unit will be milliseconds. If we write 100, it means 100 milliseconds and if we want to specify time unit then write as string. '100ms' means 100 milliseconds and '0.1s' means 0.1 second.
delay: This is the time gap between animation trigger and beginning of transition. It is written in string with time unit in string.
easing: It defines how the animations accelerates and decelerates during its runtime. Easing can be ease, ease-in, ease-out, ease-in-out etc.

Find the examples of animate with timing expression.

1.
animate(100) 
duration: 100
Animation will take place for 100ms just after animation trigger.

2.
animate( '0.6s 100ms ease-in') 
duration: 0.6s
delay: 100ms
easing: ease-in
After animation trigger there will be a delay of 100 milliseconds to start animation and then animation will take place for 0.6 seconds with ease-in function.

3.
animate('0.7s ease-out') 
duration: 0.7s
easing: ease-out
Animation will start just after trigger. Animation will take place for 0.7 seconds with ease-out function.

Find the example of animate with time expression and style.
animate('0.6s 100ms ease-in', style({
       fontSize: '19px',
       backgroundColor: 'blue' 
}))
The given style will be active from animation start to animation end.

transition

transition function is an animation-specific function. transition function runs the steps of animation for the given state change expression. State change expression is written as state1 => state2 or state2 => state1 or state1 <=> state2. transition function associates state change expression with animation steps. Find the arguments of transition function.
1. State change expression such as (state1 => state2)
2. Animation step or array of animation steps.

Find some transition function example.
1.
transition('state1 => state2', animate(...))
transition('state2 => state3', animate(...))
transition('state3 => state1', animate(...)) 
In the above transition function, animation will take place for the defined state change expression.
2. If for two states animation(...) definition is same then we can write transition function as follows.
transition('state1 <=> state2', animate(...)) 
3. If for more than one state change expression, animation(...) definition is same then state change expression will be written comma separated.
transition('state1 => state2, state2 => state3', animate(...)) 
4.
transition('* => *', animate(...)) 
Animation will take place between any state change.
5.
transition('void => *', animate(...)) 
Animation will take place from element page entry to any state. The alias of void => * is :enter and so above transition can also be written as following.
transition(':enter', animate(...)) 
6.
transition('* => void', animate(...)) 
Animation will take place from any state to no state(void state) of element. The alias of * => void is :leave and so above transition can also be written as following.
transition(':leave', animate(...)) 

Example-1: Find the example of transition. Here animate is using only time expression.
on-off-2.animation.ts
import { animate, state, style, transition, trigger } from '@angular/animations';

export const ON_OFF_2_ANIMATION =
	trigger('onOff2Trigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  color: '#1C2833',
		  fontSize: '18px',		  
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  color: '#F0F3F4',
		  fontSize: '22px',
		  transform: 'scale(1.1)'
		})),
		transition('off => on', animate('0.6s 100ms ease-in')),
		transition('on => off', animate('0.7s 100ms ease-out'))
	]); 
Find the HTML template to use trigger onOff2Trigger.
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff2Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul> 
Example-2: Find the example of transition. Here animate is using time expression and style.
on-off-3.animation.ts
import { animate, state, style, transition, trigger } from '@angular/animations';

export const ON_OFF_3_ANIMATION =
	trigger('onOff3Trigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  color: '#1C2833',
		  fontSize: '18px',		  
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  color: '#F0F3F4',
		  fontSize: '22px',
		  transform: 'scale(1.1)'
		})),
		transition('off => on', animate('0.6s 100ms ease-in',
                 		style({fontSize: '19px', backgroundColor: 'blue' }))),
		transition('on => off', animate('0.7s 100ms ease-out', 
		                style({fontSize: '19px', backgroundColor: 'red'})))
	]); 
Find the HTML template to use trigger onOff3Trigger.
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff3Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul> 

keyframes

keyframes is an animation-specific function that is used with animate function. keyframes applies different style at different offset of duration of animation. Find the code snippet.
animate('0.6s 100ms ease-in',keyframes([ 
   style({fontSize: '19px', backgroundColor: 'yellow', offset: 0.1 }),
   style({fontSize: '20px', backgroundColor: 'green', offset: 0.3 }),
   style({fontSize: '21px', backgroundColor: 'red', offset: 0.5 })
])) 
We will observe that we are using more than one style within a keyframes using offset. Here we have set more than one style that will change according to their offset within the animation start to end. If we do not use offset then it will automatically be calculated. Find the example.
on-off-4.animation.ts
import { animate, state, style, transition, trigger, keyframes } from '@angular/animations';

export const ON_OFF_4_ANIMATION =
	trigger('onOff4Trigger', [
		state('off', style({
		  backgroundColor: '#E5E7E9',
		  color: '#1C2833',
		  fontSize: '18px',		  
		  transform: 'scale(1)'
		})),
		state('on',   style({
		  backgroundColor: '#17202A',
		  color: '#F0F3F4',
		  fontSize: '22px',
		  transform: 'scale(1.1)'
		})),
		transition('off => on', animate('0.6s 100ms ease-in',keyframes([ 
		   style({fontSize: '19px', backgroundColor: 'yellow', offset: 0.1 }),
		   style({fontSize: '20px', backgroundColor: 'green', offset: 0.3 }),
		   style({fontSize: '21px', backgroundColor: 'red', offset: 0.5 })
		]))),
		transition('on => off', animate('0.7s 100ms ease-out', keyframes([ 
		   style({fontSize: '22px', backgroundColor: 'yellow', offset: 0 }),
		   style({fontSize: '21px', backgroundColor: 'green', offset: 0.2 }),
		   style({fontSize: '20px', backgroundColor: 'red', offset: 0.4 }),
		   style({fontSize: '19px', backgroundColor: 'blue', offset: 0.5 })
		])))
	]); 
In our HTML template trigger onOff4Trigger will be used as follows.
<ul [ngClass]= "'sub-menu'">
   <li *ngFor="let book of books | async" [@onOff4Trigger] = "book.state" (click)="toggle(book)"> 
	   <a>{{book.name}}</a>
   </li>
</ul> 

sequence

sequence is an animation-specific function. It is used within a transition or group function. sequence function will contain the array of style and animate functions. They will execute in sequence. Find the code snippet.
transition('* => void', sequence([ 
    style({backgroundColor: '#0D6063'}),
    animate('0.6s ease-out', style({transform: 'rotate(-270deg)', opacity: 0}))
])) 
Using keyword sequence is not necessary. It is default, we can directly use array of style and animate functions.
transition('* => void', [ 
    style({backgroundColor: '#0D6063'}),
    animate('0.6s ease-out', style({transform: 'rotate(-270deg)', opacity: 0}))
]) 

group

group is an animation-specific function that can be used within a transition or sequence function. group contains the entries of animations steps that run in parallel.
transition('void => *', [
   style({
        backgroundColor: '#E3E8EC',
        transform: 'translateX(300%)',
        opacity: 0
   }),
   group([
        animate('0.5s 0.1s ease-in', style({
             transform: 'translateX(0)',
        })),
        animate('0.3s 0.1s ease', style({
             opacity: 1
        }))
   ])
]) 
In the above code snippet transition is using state change expression and sequence. Within the sequence we are using style and group and group is using the entries of animate functions. These animate functions will run in parallel for the given durations.

(void => *) alias (:enter) and (* => void) alias (:leave)

Here we will provide examples of void => * and * => void state change expression. void => * has the alias :enter and * => void has alias :leave. void state means a state for the element when element is not available in DOM. * is the default state. This is a state which has not been declared within the trigger function. * state is used for dynamic start and ending state in animation. Now find the examples.
Example-1: Using (void => *) and (* => void)

round-anticlock.animation.ts
import { animate, state, style, transition, trigger, sequence } from '@angular/animations';

export const ROUND_ANTICLOCK_ANIMATION =
  trigger('roundAntiClockTrigger', [
    state('in', style({
	    backgroundColor: '#E5E7E9',
	    color: '#1B2172'
    })),  
    transition('void => *', sequence([
        style({
		 transform: 'rotate(270deg)',
  		 opacity: 0,
		 backgroundColor: '#0D6063'
	}),
        animate('0.6s ease-in-out')
    ])),
    transition('* => void', sequence([ 
	style({backgroundColor: '#0D6063'}),
        animate('0.6s ease-out', style({transform: 'rotate(-270deg)', opacity: 0}))
    ]))
  ]);  
In the above animation code, style is using transform CSS property. It applies 2D or 3D transformation to an element. The value of transform can be translate, rotate, scale, move, skew, etc.
addbook.component.ts
import { Component, HostBinding } from '@angular/core';
import { Router } from '@angular/router'; 

import { BookService } from './book.service';
import { Book } from './book';
import { ROUND_ANTICLOCK_ANIMATION }   from './animations/round-anticlock.animation';
@Component({
  templateUrl: './addbook.component.html',
  styles: [ ':host { position: absolute; top: 20%; left: 5%; border: 3px solid black; }' ],    
  animations: [ 
     ROUND_ANTICLOCK_ANIMATION
  ]
})
export class AddBookComponent {
  @HostBinding('@roundAntiClockTrigger') roundAntiClockTrigger = 'in';
  book = {} as Book;
  constructor(private bookService: BookService, private router: Router) {
  }
  add() {
    this.bookService.addBook(this.book).then(
	 () => this.router.navigate(['/book'])
    );
  } 
} 
To apply animation on host element we need to use HostBinding. We need to pass the trigger name to HostBinding.
@HostBinding('@roundAntiClockTrigger') roundAntiClockTrigger = 'in'; 
'in' is the initial state name of animation defined in animation trigger function. HostBinding can also bind CSS property to host element such as
@HostBinding('style.display')   display = 'block';
@HostBinding('style.position')  position = 'absolute'; 
To bind CSS property to host element we can also use component style special selector :host as given below.
:host { position: absolute; top: 20%; left: 5%; border: 3px solid black; } 
For more detail of component style special selectors, visit following link.

Angular Component Styles :host, :host-context, /deep/ Selector Example

Now find the html template.
addbook.component.html
<h3>Add Book</h3>
<p>Enter Name: <input [(ngModel)]="book.name"> </p>
<p>Enter Author: <input [(ngModel)]="book.author"> </p>
<p> <button type="button" (click)="add()">Add</button> </p> 
Example-2: Using (:enter) and (:leave)

We have already discussed that :enter is the alias of void => * state change expression and :leave is the alias of * => void state change expression. Now find the example.
fly-in-out.animation.ts
import { animate, state, style, transition, trigger, group } from '@angular/animations';

export const FLY_IN_OUT_ANIMATION =
  trigger('flyInOutTrigger', [
    state('in', style({
	    backgroundColor: '#7BBEFC',
	    color: '#080809', 
	    transform: 'translateX(0)', 
	    opacity: 1
    })),
    transition(':enter', [
      style({
	        backgroundColor: '#E3E8EC',
	        transform: 'translateX(300%)',
		opacity: 0
      }),
      group([
        animate('0.5s 0.1s ease-in', style({
            transform: 'translateX(0)',
        })),
        animate('0.3s 0.1s ease', style({
            opacity: 1
        }))
      ])
    ]),
    transition(':leave', [
      style({
	   backgroundColor: '#9DCEFC',
      }),	
      group([
        animate('0.5s ease-out', style({
            transform: 'translateX(300%)'
        })),
        animate('0.3s 0.1s ease', style({
            opacity: 0
        }))
      ])
    ])
  ]); 
book-detail.component.ts
import { Component, OnInit, HostBinding } from '@angular/core';
import { FLY_IN_OUT_ANIMATION }   from './animations/fly-in-out.animation';

import { BookService } from './book.service';
import { Book } from './book';

@Component({
  templateUrl: './book-detail.component.html',
  styles: [ ':host { position: absolute; top: 20%; left: 5%; border: 3px solid black; }' ],
  animations: [ 
    FLY_IN_OUT_ANIMATION
  ]
})
export class BookDetailComponent implements OnInit { 
  @HostBinding('@flyInOutTrigger') flyInOutTrigger = 'in';
  books = = {} as Promise<Book[]>;
  constructor(private bookService: BookService) {
  }
  ngOnInit() {
     this.books = this.bookService.getBooks();
  }
} 
book-detail.component.html
<h3>Book Details</h3>
<p *ngFor="let book of books | async"> 
	<b>Id:</b> {{book.id}}, <b>Name:</b> {{book.name}}, <b>Author:</b> {{book.author}}
</p> 
Find the output.
Angular Animations Example

Application Component and Module used in Demo

app.component.ts
import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  template: `
	<nav [ngClass] = "'parent-menu'">
	  <ul>
            <li><a routerLink="/book" routerLinkActive="active">Book</a></li>	  
            <li><a routerLink="/add-book" routerLinkActive="active">Add Book</a></li>			 
	    <li><a routerLink="/book-detail" routerLinkActive="active">Book Details</a></li>
	  </ul> 
	</nav>  
	<router-outlet></router-outlet>	
  `
})
export class AppComponent { 
} 
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { BookComponent }  from './book.component';
import { AddBookComponent }  from './addbook.component';
import { BookDetailComponent }  from './book-detail.component';

const routes: Routes = [
	{
	   path: 'book',
	   component: BookComponent,
	},
	{
	   path: 'add-book',
	   component: AddBookComponent
	},	
	{
	   path: 'book-detail',
	   component: BookDetailComponent
	},	
	{
	   path: '',
	   redirectTo: '/book',
	   pathMatch: 'full'
	}	
];
@NgModule({
  imports: [ 
          RouterModule.forRoot(routes) 
  ],
  exports: [ 
          RouterModule 
  ]
})
export class AppRoutingModule{ }  
app.module.ts
import { NgModule }   from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent }  from './app.component';
import { BookComponent }  from './book.component';
import { AddBookComponent }  from './addbook.component';
import { BookDetailComponent }  from './book-detail.component';
import { BookService }  from './book.service';
import { AppRoutingModule }  from './app-routing.module';

@NgModule({
  imports: [     
        BrowserModule,
	FormsModule,
	AppRoutingModule,
	BrowserAnimationsModule
  ],
  declarations: [
        AppComponent,
        BookComponent,
	AddBookComponent,
	BookDetailComponent
  ],
  providers: [ BookService ],
  bootstrap: [ AppComponent ]
})
export class AppModule { } 
styles.css
.parent-menu ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: #333;
}
.parent-menu li {
    float: left;
}
.parent-menu li a {
    display: block;
    color: white;
    text-align: center;
    padding: 15px 15px;
    text-decoration: none;
}
.parent-menu li a:hover:not(.active) {
    background-color: #111;
}
.parent-menu .active{
    background-color: #4CAF50;
}
.sub-menu ul {
   list-style-type: none;
   padding: 0;
}
.sub-menu li {
   display: inline-block;
   width: 120px;
   line-height: 50px;
   padding: 0 10px;
   box-sizing: border-box;
   background-color: #eee;
   border-radius: 4px;
   margin: 10px;
   cursor: pointer;
   overflow: hidden;
   white-space: nowrap;
} 

References

Introduction to Angular animations
Animations API

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us