How can we create a shake animation using Angular 6 animations? The animation should look like 'shake' animation in Animate.css

- 1,002
- 2
- 17
- 22
3 Answers
This is a little bit tricky, if you want to apply the animation to several elements within one component in Angular 6:
app.component.html:
<p [@shakeit]="this.states['state1']" (click)="shakeMe('state1')" (@shakeit.done)="shakeEnd('state1', $event)">Click me</p>
<p [@shakeit]="this.states['state2']" (click)="shakeMe('state2')" (@shakeit.done)="shakeEnd('state2', $event)">Click me</p>
app.component.ts:
import { Component } from '@angular/core';
import { trigger,state,style,transition,animate,keyframes } from '@angular/animations';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
animations: [
trigger('shakeit', [
state('shakestart', style({
transform: 'scale(1)',
})),
state('shakeend', style({
transform: 'scale(1)',
})),
transition('shakestart => shakeend', animate('1000ms ease-in', keyframes([
style({transform: 'translate3d(-1px, 0, 0)', offset: 0.1}),
style({transform: 'translate3d(2px, 0, 0)', offset: 0.2}),
style({transform: 'translate3d(-4px, 0, 0)', offset: 0.3}),
style({transform: 'translate3d(4px, 0, 0)', offset: 0.4}),
style({transform: 'translate3d(-4px, 0, 0)', offset: 0.5}),
style({transform: 'translate3d(4px, 0, 0)', offset: 0.6}),
style({transform: 'translate3d(-4px, 0, 0)', offset: 0.7}),
style({transform: 'translate3d(2px, 0, 0)', offset: 0.8}),
style({transform: 'translate3d(-1px, 0, 0)', offset: 0.9}),
]))),
])]
})
export class AppComponent {
states = {};
constructor() {
this.states['state1'] = 'shakestart';
this.states['state2'] = 'shakestart';
}
shakeMe(stateVar: string) {
this.states[stateVar] = (this.states[stateVar] === 'shakestart' ? 'shakeend' : 'shakestart');
}
shakeEnd(stateVar: string, event) {
this.states[stateVar] = 'shakeend';
}
}
You see, I use a dictionary for the animation states of the different html elements. Therefore, it is a little bit more work and overhead if you want to use Angular 6.
shakeMe
method starts the animation.
However, I would recommend to just use CSS keyframes because it is easier to realize for several html elements. The following example does the same animation. You just have to apply the correct css class to the html element.
.shakeit:hover {
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000px;
}
@keyframes shake {
10%, 90% {
transform: translate3d(-1px, 0, 0);
}
20%, 80% {
transform: translate3d(2px, 0, 0);
}
30%, 50%, 70% {
transform: translate3d(-4px, 0, 0);
}
40%, 60% {
transform: translate3d(4px, 0, 0);
}
}
<h2 class="shakeit">Hover me</h2>

- 659
- 6
- 9
-
2This answer would be significantly improved by putting the code into a [snippet](https://blog.stackoverflow.com/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/). Using a snippet also makes it more likely for it to be up-voted, because people can quickly verify that your code functions correctly. While snippets shouldn't always be used, for JavaScript/HTML/CSS based questions and answers, they can significantly improve communicating both the problem and solution. When possible to use, a snippet is better than runable code examples that are off-site (e.g. JSFiddle). – Makyen Oct 20 '18 at 19:51
-
1Thank you for the hint. I did not know that there are html/css/javascript runnable build-in code snippets. I changed my answer. Thank you! – kedenk Oct 21 '18 at 12:30
Here is a simple solution using ngx-animate
.
Template
<p [@shake]="showAnimation">Hello World</p>
Typescript
import { trigger, transition, useAnimation } from '@angular/animations';
import { shake } from 'ngx-animate'; // npm i ngx-animate
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
animations: [
trigger('shake', [transition('* => *', useAnimation(shake))])
],
})
export class AppComponent {
showAnimation: boolean = false;
constructor() {
this.showAnimation = !this.showAnimation;
}
}

- 3,213
- 3
- 40
- 59
I created a service for shake animations. Just copy and paste the code and use it like in the app.component example here
One of the cool benefits – it does not allow users to trigger shaking if the shaking isn't finished.
The code of the service:
import { Injectable } from "@angular/core";
import {
animate,
style,
transition,
trigger,
keyframes
} from "@angular/animations";
const shaker = (amount: number) => {
const shake = (function* shaker() {
while (true) {
yield 0;
yield -10;
yield 0;
yield 10;
}
})();
return new Array(amount).fill(0).map(() =>
style({
transform: `translateX(${shake.next().value}px)`
})
);
};
export const shake = trigger("shake", [
transition("false => true", [
animate("{{shakeDuration}}s linear", keyframes(shaker(7)))
])
]);
@Injectable({
providedIn: "root"
})
export class ShakeService {
isShaking = false;
shakeDuration = 0.3;
toggle() {
if (this.isShaking) return;
this.isShaking = true;
setTimeout(() => {
this.isShaking = false;
}, this.shakeDuration * 1000);
}
public get animation() {
return {
value: this.isShaking,
params: { shakeDuration: this.shakeDuration }
};
}
}
Import shake
and ShakeService
in your component from that service file like this:
import { Component } from "@angular/core";
import { shake, ShakeService } from "./shake.service";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
animations: [shake]
})
export class AppComponent {
constructor(public shaker: ShakeService) {}
}
Use it in your template like this:
<div [@shake]="shaker.animation" (click)="shaker.toggle()">
<p>Click on me to shake</p>
</div>

- 11
- 2