Motion One is a relatively fresh animation library that runs on the Web Animations API. If you have worked with Popmotion or Greensock in the past, you will likely recognize the overall syntax immediately.
The goal of this post is to demonstrate how Motion One can be integrated into an Angular project. I will cover the setup steps, build a straightforward animation, and then look at the spring and timeline utilities that Motion One ships with.
You can find a live, interactive demo as part of my Angular Animation Explorer.
Installation
The first step is to install the library through npm with the command below.
npm install --save motion
If TypeScript complains about typings, you can try adding
skipLibCheck: trueto your tsconfig.json.
A First Animation
To target an element in your template, you must assign it an id so it can be referenced from your TypeScript file.
<div #myElement>...</div>
Once the id is in place, the element can be pulled into your component class with Angular's ViewChild decorator.
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
...
})
export class MotionOneDemoComponent {
@ViewChild('myElement') myElement: ElementRef;
}
With the element reference available, you are ready to invoke Motion One's animation APIs to bring it to life.
import { Component, ViewChild, ElementRef } from '@angular/core';
import { animate } from 'motion';
@Component({
...
})
export class MotionOneDemoComponent {
@ViewChild('myElement') myElement: ElementRef;
animateMyElement(): void {
animate(
this.myElement.nativeElement,
{ rotate: 180 },
{ duration: 0.5, easing: 'ease-in' }
).finished.then(() => {
// animation completed
})
.catch(() => {
// if an error happens
});
}
}
Springs and Glides
Motion One includes preconfigured easings like spring and glide. These are used by passing their respective functions into the animation options, along with any extra configuration they accept. The following snippet illustrates how a basic spring animation is put together:
import { Component, ViewChild, ElementRef } from '@angular/core';
import { animate, spring } from 'motion';
@Component({
...
})
export class MotionOneDemoComponent {
@ViewChild('myElement') myElement: ElementRef;
animateMyElement(): void {
animate(
this.myElement.nativeElement,
{ rotate: 180 },
{ duration: 0.5, easing: spring() } // 👈 modify the easing
).finished.then(() => {
// animation completed
})
.catch(() => {
// if an error happens
});
}
}
Building Timelines
Timelines are another notable feature in Motion One's toolbox. By constructing an array of animations and feeding it to the timeline function, you can orchestrate multiple animations on different elements simultaneously or in sequence.
The timeline API behaves much like Greensock's timeline. The example below demonstrates how a box can be translated through a chained sequence of keyframes.
import { Component, ViewChild, ElementRef } from '@angular/core';
import { timeline } from 'motion';
@Component({
...
})
export class MotionOneDemoComponent {
@ViewChild('myElement') myElement: ElementRef;
animateMyElement(): void {
const sequence = [
[this.myElement.nativeElement, { x: 100 }, { duration: 0.5 }],
[this.myElement.nativeElement, { y: 100 }, { duration: 0.5 }],
[this.myElement.nativeElement, { x: 0, y: 0 }, { duration: 1 }],
];
timeline(sequence)
.finished.then(() => {
// animation completed
})
.catch(() => {
// if an error happens
});
}
}
Final Thoughts
Compared to many established animation libraries, Motion One is still maturing. Even so, it already offers a rich feature set, solid performance, and a straightforward developer experience. This guide only scratches the surface of what the library can do. More advanced topics are on the horizon, and I plan to write a follow-up post that explores them in greater detail.
For further questions or feedback, feel free to leave a comment or reach out on Twitter at @williamjuan27



