use-web-animations
😎 🍿 React hook for highly-performant and manipulable animations using Web Animations API.
Top Related Projects
Open source, production-ready animation and gesture library for React
A zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with React, Vue, or any other JavaScript application.
JavaScript animation engine
GSAP (GreenSock Animation Platform), a JavaScript animation library for the modern web
Animate on scroll library
🍿 A cross-browser library of CSS animations. As easy to use as an easy thing.
Quick Overview
use-web-animations
is a React hook that provides a simple and intuitive way to create and control Web Animations API animations. It allows developers to easily animate elements in React applications using a declarative approach, leveraging the power of the native Web Animations API.
Pros
- Easy integration with React components
- Lightweight and performant, utilizing native browser APIs
- Supports keyframe animations and timing options
- Provides a simple API for controlling animations (play, pause, reverse, etc.)
Cons
- Limited browser support for older versions (requires polyfill for some browsers)
- May have a learning curve for developers unfamiliar with Web Animations API
- Less extensive feature set compared to some larger animation libraries
Code Examples
Creating a simple fade-in animation:
import useWebAnimations from "@wellyshen/use-web-animations";
const { ref, playState, getAnimation } = useWebAnimations({
keyframes: [
{ opacity: 0 },
{ opacity: 1 }
],
timing: {
duration: 1000,
fill: "forwards"
}
});
return <div ref={ref}>Fade me in</div>;
Animating multiple properties with easing:
const { ref } = useWebAnimations({
keyframes: [
{ transform: "scale(1)", backgroundColor: "#fff" },
{ transform: "scale(1.5)", backgroundColor: "#ff0000" }
],
timing: {
duration: 2000,
easing: "ease-in-out",
iterations: Infinity,
direction: "alternate"
}
});
return <div ref={ref}>Grow and change color</div>;
Controlling animation playback:
const { ref, playState, getAnimation } = useWebAnimations();
const handleClick = () => {
const animation = getAnimation();
if (playState === "running") {
animation.pause();
} else {
animation.play();
}
};
return <button ref={ref} onClick={handleClick}>Toggle Animation</button>;
Getting Started
-
Install the package:
npm install @wellyshen/use-web-animations
-
Import and use in your React component:
import useWebAnimations from "@wellyshen/use-web-animations"; function MyComponent() { const { ref } = useWebAnimations({ keyframes: [ { transform: "translateY(0px)" }, { transform: "translateY(100px)" } ], timing: { duration: 1000, iterations: Infinity, direction: "alternate", easing: "ease-in-out" } }); return <div ref={ref}>Animated element</div>; }
-
Optionally, import the polyfill for broader browser support:
import "@wellyshen/use-web-animations/polyfill";
Competitor Comparisons
Open source, production-ready animation and gesture library for React
Pros of motion
- More comprehensive animation library with a wider range of features
- Better documentation and community support
- Supports server-side rendering and static site generation
Cons of motion
- Larger bundle size, which may impact performance for smaller projects
- Steeper learning curve due to more complex API
Code Comparison
use-web-animations:
const { ref, playState, getAnimation } = useWebAnimations({
keyframes: [{ transform: 'translateX(0)' }, { transform: 'translateX(100px)' }],
timing: { duration: 1000, iterations: Infinity },
});
motion:
<motion.div
animate={{ x: 100 }}
transition={{ duration: 1, repeat: Infinity }}
/>
Summary
motion is a more feature-rich animation library with better documentation and community support, making it suitable for complex projects. However, it comes with a larger bundle size and a steeper learning curve. use-web-animations offers a simpler API and smaller footprint, which may be preferable for smaller projects or those prioritizing performance. The code comparison shows that motion provides a more declarative approach to animations, while use-web-animations offers more fine-grained control over keyframes and timing.
A zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with React, Vue, or any other JavaScript application.
Pros of auto-animate
- Framework-agnostic, works with various JavaScript frameworks and vanilla JS
- Simpler API, requiring less setup and configuration
- Automatically handles enter/exit animations for added/removed elements
Cons of auto-animate
- Less fine-grained control over individual animation properties
- Limited to a predefined set of animation types
- May not be suitable for complex, custom animations
Code Comparison
auto-animate:
import { autoAnimate } from '@formkit/auto-animate'
function MyComponent() {
const parent = useRef(null)
useEffect(() => {
parent.current && autoAnimate(parent.current)
}, [parent])
return <div ref={parent}>...</div>
}
use-web-animations:
import useWebAnimations from '@wellyshen/use-web-animations'
function MyComponent() {
const { ref, playState, getAnimation } = useWebAnimations({
keyframes: [...],
timing: { duration: 1000, iterations: Infinity }
})
return <div ref={ref}>...</div>
}
Both libraries aim to simplify animations in web applications, but they take different approaches. auto-animate focuses on ease of use and automatic animations for common scenarios, while use-web-animations provides more control and aligns closely with the Web Animations API. The choice between them depends on the specific needs of your project and the level of animation complexity required.
JavaScript animation engine
Pros of anime
- More comprehensive animation library with a wider range of features
- Supports SVG animations and morphing
- Better performance for complex animations due to optimized engine
Cons of anime
- Larger file size, which may impact load times
- Steeper learning curve due to more complex API
- Not specifically designed for React, requiring additional setup
Code Comparison
use-web-animations:
const { ref, playState, getAnimation } = useWebAnimations({
keyframes: [{ transform: 'translateX(0px)' }, { transform: 'translateX(100px)' }],
timing: { duration: 1000, iterations: Infinity },
});
anime:
anime({
targets: '.element',
translateX: 100,
duration: 1000,
loop: true
});
Key Differences
- use-web-animations is a React hook, making it more integrated with React components
- anime provides a more flexible API for creating complex animations
- use-web-animations relies on the Web Animations API, while anime is a standalone library
- anime offers more advanced features like timeline and staggering effects
Use Cases
use-web-animations is ideal for:
- React projects requiring simple animations
- Developers who prefer working with hooks
anime is better suited for:
- Projects requiring complex animations or SVG morphing
- Applications not limited to React
- Scenarios where broad browser support is crucial
GSAP (GreenSock Animation Platform), a JavaScript animation library for the modern web
Pros of GSAP
- More comprehensive animation capabilities, including complex timelines and advanced easing functions
- Extensive browser support, including older versions
- Larger ecosystem with plugins and additional tools
Cons of GSAP
- Steeper learning curve due to its extensive feature set
- Larger file size, which may impact load times for smaller projects
- Commercial license required for some use cases
Code Comparison
use-web-animations:
import useWebAnimations from '@wellyshen/use-web-animations';
const { ref, playState, getAnimation } = useWebAnimations({
keyframes: [{ transform: 'translateX(0)' }, { transform: 'translateX(100px)' }],
timing: { duration: 1000, iterations: Infinity },
});
GSAP:
import { gsap } from 'gsap';
gsap.to('.element', {
x: 100,
duration: 1,
repeat: -1,
});
Summary
GSAP offers a more powerful and flexible animation solution with broader browser support, while use-web-animations provides a simpler, React-focused approach using the Web Animations API. GSAP is better suited for complex animations and larger projects, whereas use-web-animations is ideal for simpler animations in React applications with modern browser support.
Animate on scroll library
Pros of AOS
- Simpler to use, with a more straightforward API
- Works with any JavaScript framework or vanilla HTML/CSS
- Extensive library of pre-built animations
Cons of AOS
- Less flexible for creating custom animations
- Heavier library size compared to use-web-animations
- Limited control over animation timing and sequencing
Code Comparison
AOS:
<div data-aos="fade-up" data-aos-duration="1000">
Animate me!
</div>
use-web-animations:
const { ref } = useWebAnimations({
keyframes: [
{ opacity: 0, transform: 'translateY(50px)' },
{ opacity: 1, transform: 'translateY(0)' }
],
timing: { duration: 1000, fill: 'forwards' }
});
return <div ref={ref}>Animate me!</div>;
AOS provides a simpler, attribute-based approach for adding animations, while use-web-animations offers more programmatic control through React hooks. AOS is easier to implement for basic animations, but use-web-animations provides greater flexibility for complex, custom animations within React applications.
Both libraries have their strengths, and the choice between them depends on the specific project requirements, desired level of control, and the development framework being used.
🍿 A cross-browser library of CSS animations. As easy to use as an easy thing.
Pros of animate.css
- Simpler to implement, requiring only CSS classes
- Extensive library of pre-built animations
- Widely adopted and well-documented
Cons of animate.css
- Less flexible for custom animations
- Potentially larger file size if not optimized
- Limited control over animation timing and behavior
Code Comparison
animate.css:
<div class="animate__animated animate__fadeIn">
This element will fade in
</div>
use-web-animations:
import useWebAnimations from "@wellyshen/use-web-animations";
const { ref } = useWebAnimations({
keyframes: { opacity: [0, 1] },
timing: { duration: 1000, fill: "forwards" },
});
return <div ref={ref}>This element will fade in</div>;
Key Differences
- animate.css relies on CSS classes, while use-web-animations uses JavaScript hooks
- use-web-animations offers more programmatic control over animations
- animate.css provides a larger set of ready-to-use animations
- use-web-animations integrates more seamlessly with React components
Use Cases
- animate.css: Quick implementation of common animations, static websites
- use-web-animations: Complex, dynamic animations in React applications, custom animation sequences
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
USE-WEB-ANIMATIONS
Using Web Animations API (a.k.a WAAPI) in the React hook way. Let's create highly-performant, flexible and manipulable web animations in the modern world. Hope you guys ðð» it!
â¤ï¸ it? âï¸ it on GitHub or Tweet about it.
â¡ï¸ Try yourself: https://use-web-animations.netlify.app
â¡ï¸ Try yourself: https://use-web-animations.netlify.app#animations
Features
- ð Animate on the Web with highly-performant and manipulable way, using Web Animations API.
- ð£ Easy to use, based on React hook.
- ð Super flexible API design that can cover all the cases that you need.
- ð Built-ins animations for you, based on Animate.css.
- ð© Supports custom
refs
for some reasons. - ð Supports TypeScript type definition.
- ðï¸ Server-side rendering compatibility.
- ð¦ Tiny size (~ 4.4kB gzipped). No external dependencies, aside for the
react
.
Requirement
To use use-web-animations
, you must use react@16.8.0
or greater which includes hooks.
Installation
This package is distributed via npm.
$ yarn add @wellyshen/use-web-animations
# or
$ npm install --save @wellyshen/use-web-animations
Before We Start
With the Web Animations API, we can move interactive animations from stylesheets to JavaScript, separating presentation from behavior. The API was designed based on the concept of the CSS Animations but there're still some differences between them. I strongly recommend you to read the documentation before we dive into this hook.
Usage
The API design of the hook not only inherits the DX of the Web Animations API but also provides useful features and sugar events to us. Here are some examples to show you how does it work.
â ï¸ Most modern browsers support Web Animations API natively. You can also use polyfill for full browser support.
Basic Usage
Create an animation by the keyframes
and animationOptions
options (these are the parameters of the Element.animate()
).
ð¡ This hook supports the pseudoElement property via the
animationOptions
option.
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const { ref, playState } = useWebAnimations({
keyframes: {
transform: "translateX(500px)", // Move by 500px
background: ["red", "blue", "green"], // Go through three colors
},
animationOptions: {
delay: 500, // Start with a 500ms delay
duration: 1000, // Run for 1000ms
iterations: 2, // Repeat once
direction: "alternate", // Run the animation forwards and then backwards
easing: "ease-in-out", // Use a fancy timing function
},
onReady: ({ playState, animate, animation }) => {
// Triggered when the animation is ready to play
},
onUpdate: ({ playState, animate, animation }) => {
// Triggered when the animation enters the running state or changes state
},
onFinish: ({ playState, animate, animation }) => {
// Triggered when the animation enters the finished state
},
// More useful options...
});
return (
<div className="container">
<p>ð¿ Animation is {playState}</p>
<div className="target" ref={ref} />
</div>
);
};
For browsers that don't yet support the onReady
and onFinish
events, we can use the onUpdate
to monitor the animation's state instead.
let prevPending = true;
const App = () => {
const { ref } = useWebAnimations({
// ...
onUpdate: ({ playState, animation: { pending } }) => {
if (prevPending && !pending) {
console.log("Animation is ready to play");
}
prevPending = pending;
if (playState === "finished") {
console.log("Animation has finished playing");
}
},
});
// ...
};
Setting/Updating Animation
The keyframes
and animationOptions
are cached when the hook is mounted. However, we can set/update the animation by the animation
method.
const { animation } = useWebAnimations();
const changeAnim = () =>
animation({
keyframes: { transform: ["translateX(0)", "translateX(100px)"] },
animationOptions: 1000,
id: "123",
playbackRate: 1,
autoPlay: true,
});
Playback Control
The shortcoming with existing technologies was the lack of playback control. The Web Animations API provides several useful methods for controlling playback: play, pause, reverse, cancel, finish, seek, control speed via the methods of the Animation interface. This hook exposes the animation instance for us to interact with animations, we can access it by the getAnimation()
return value.
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const { ref, playState, getAnimation } = useWebAnimations({
playbackRate: 0.5, // Change playback rate, default is 1
autoPlay: false, // Automatically starts the animation, default is true
keyframes: { transform: "translateX(500px)" },
animationOptions: { duration: 1000, fill: "forwards" },
});
const play = () => {
getAnimation().play();
};
const pause = () => {
getAnimation().pause();
};
const reverse = () => {
getAnimation().reverse();
};
const cancel = () => {
getAnimation().cancel();
};
const finish = () => {
getAnimation().finish();
};
const seek = (e) => {
const animation = getAnimation();
const time = (animation.effect.getTiming().duration / 100) * e.target.value;
animation.currentTime = time;
};
const updatePlaybackRate = (e) => {
getAnimation().updatePlaybackRate(e.target.value);
};
return (
<div className="container">
<button onClick={play}>Play</button>
<button onClick={pause}>Pause</button>
<button onClick={reverse}>Reverse</button>
<button onClick={cancel}>Cancel</button>
<button onClick={finish}>Finish</button>
<input type="range" onChange={seek} />
<input type="number" defaultValue="1" onChange={updatePlaybackRate} />
<div className="target" ref={ref} />
</div>
);
};
Getting Animation's Information
When using the Web Animations API, we can get the information of an animation via the properties of the Animation interface. However, we can get the information of an animation by the getAnimation()
return value as well.
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const { ref, getAnimation } = useWebAnimations({
keyframes: { transform: "translateX(500px)" },
animationOptions: { duration: 1000, fill: "forwards" },
});
const speedUp = () => {
const animation = getAnimation();
animation.updatePlaybackRate(animation.playbackRate * 0.25);
};
const jumpToHalf = () => {
const animation = getAnimation();
animation.currentTime = animation.effect.getTiming().duration / 2;
};
return (
<div className="container">
<button onClick={speedUp}>Speed Up</button>
<button onClick={jumpToHalf}>Jump to Half</button>
<div className="target" ref={ref} />
</div>
);
};
The animation instance isn't a part of React state, which means we need to access it by the getAnimation()
whenever we need. If you want to monitor an animation's information, here's the onUpdate
event for you. The event is implemented by the requestAnimationFrame internally and the event callback is triggered when the animation enters running
state or changes state.
import { useState } from "react";
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const [showEl, setShowEl] = useState(false);
const { ref } = useWebAnimations({
keyframes: { transform: "translateX(500px)" },
animationOptions: { duration: 1000, fill: "forwards" },
onUpdate: ({ animation }) => {
if (animation.currentTime > animation.effect.getTiming().duration / 2)
setShowEl(true);
},
});
return (
<div className="container">
{showEl && <div className="some-element" />}
<div className="target" ref={ref} />
</div>
);
};
Dynamic Interactions with Animation
We can create and play an animation at the animationOptions
we want by the animate
method, which is implemented based on the Element.animate(). It's useful for interactions and the composite modes.
Let's create a mouse interaction effect:
import { useEffect } from "react";
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const { ref, animate } = useWebAnimations();
useEffect(() => {
document.addEventListener("mousemove", (e) => {
// The target will follow the mouse cursor
animate({
keyframes: { transform: `translate(${e.clientX}px, ${e.clientY}px)` },
animationOptions: { duration: 500, fill: "forwards" },
});
});
}, [animate]);
return (
<div className="container">
<div className="target" ref={ref} />
</div>
);
};
Create a bounce effect via lifecycle and composite mode:
import useWebAnimations from "@wellyshen/use-web-animations";
const App = () => {
const { ref, animate } = useWebAnimations({
id: "fall", // Set animation id, default is empty string
keyframes: [{ top: 0, easing: "ease-in" }, { top: "500px" }],
animationOptions: { duration: 300, fill: "forwards" },
onFinish: ({ animate, animation }) => {
// Lifecycle is triggered by each animation, we can check the id to prevent animation from repeating
if (animation.id === "bounce") return;
animate({
id: "bounce",
keyframes: [
{ top: "500px", easing: "ease-in" },
{ top: "10px", easing: "ease-out" },
],
animationOptions: { duration: 300, composite: "add" },
});
},
});
return (
<div className="container">
<div className="target" ref={ref} />
</div>
);
};
â ï¸ Composite modes isn't fully supported by all the browsers, please check the browser compatibility carefully before using it.
Use Built-in Animations
Too lazy to think about animation? We provide a collection of ready-to-use animations for you, they are implemented based on Animate.css.
ðð» Check out the demo.
import useWebAnimations, { bounce } from "@wellyshen/use-web-animations";
const App = () => {
// Add a pre-defined effect to the target
const { ref } = useWebAnimations({ ...bounce });
return (
<div className="container">
<div className="target" ref={ref} />
</div>
);
};
We can customize the built-in animation by overriding its properties:
const { keyframes, animationOptions } = bounce;
const { ref } = useWebAnimations({
keyframes,
animationOptions: {
...animationOptions,
delay: 1000, // Delay 1s
duration: animationOptions.duration * 0.75, // Speed up the animation
},
});
See all available animations
Attention seekers
- bounce
- flash
- pulse
- rubberBand
- shakeX
- shakeY
- headShake
- swing
- tada
- wobble
- jello
- heartBeat
Back entrances
- backInDown
- backInLeft
- backInRight
- backInUp
Back exits
- backOutDown
- backOutLeft
- backOutRight
- backOutUp
Bouncing entrances
- bounceIn
- bounceInDown
- bounceInLeft
- bounceInRight
- bounceInUp
Bouncing exits
- bounceOut
- bounceOutDown
- bounceOutLeft
- bounceOutRight
- bounceOutUp
Fading entrances
- fadeIn
- fadeInDown
- fadeInDownBig
- fadeInLeft
- fadeInLeftBig
- fadeInRight
- fadeInRightBig
- fadeInUp
- fadeInUpBig
- fadeInTopLeft
- fadeInTopRight
- fadeInBottomLeft
- fadeInBottomRight
Fading exits
- fadeOut
- fadeOutDown
- fadeOutDownBig
- fadeOutLeft
- fadeOutLeftBig
- fadeOutRight
- fadeOutRightBig
- fadeOutUp
- fadeOutUpBig
- fadeOutTopLeft
- fadeOutTopRight
- fadeOutBottomLeft
- fadeOutBottomRight
Flippers
- flip
- flipInX
- flipInY
- flipOutX
- flipOutY
Lightspeed
- lightSpeedInRight
- lightSpeedInLeft
- lightSpeedOutRight
- lightSpeedOutLeft
Rotating entrances
- rotateIn
- rotateInDownLeft
- rotateInDownRight
- rotateInUpLeft
- rotateInUpRight
Rotating exits
- rotateOut
- rotateOutDownLeft
- rotateOutDownRight
- rotateOutUpLeft
- rotateOutUpRight
Specials
- hinge
- jackInTheBox
- rollIn
- rollOut
Zooming entrances
- zoomIn
- zoomInDown
- zoomInLeft
- zoomInRight
- zoomInUp
Zooming exits
- zoomOut
- zoomOutDown
- zoomOutLeft
- zoomOutRight
- zoomOutUp
Sliding entrances
- slideInDown
- slideInLeft
- slideInRight
- slideInUp
Sliding exits
- slideOutDown
- slideOutLeft
- slideOutRight
- slideOutUp
Use Your Own ref
In case of you had a ref already or you want to share a ref for other purposes. You can pass in the ref instead of using the one provided by this hook.
const ref = useRef();
const { playState } = useWebAnimations({ ref });
Working in TypeScript
This hook supports TypeScript, you can tell the hook what type of element you are going to animate through the generic type:
const App = () => {
const { ref } = useWebAnimations<HTMLDivElement>();
return <div ref={ref} />;
};
ð¡ For more available types, please check it out.
API
const returnObj = useWebAnimations(options?: object);
Return Object
It's returned with the following properties.
Key | Type | Default | Description |
---|---|---|---|
ref | object | Used to set the target element for animating. | |
playState | string | undefined | Describes the playback state of an animation. | |
getAnimation | function | Access the animation instance for playback control, animation's information and more. | |
animate | function | Imperatively set/update the animation. Useful for interactive animations and composite animations. |
Parameter
The options
provides the following configurations and event callbacks for you.
Key | Type | Default | Description |
---|---|---|---|
ref | object | For some reasons, you can pass in your own ref instead of using the built-in. | |
id | string | "" | Sets the ID of an animation, implemented based on the Animation.id. |
playbackRate | number | 1 | Sets the playback rate of an animation, implemented based on the Animation.playbackRate. |
autoPlay | boolean | true | Automatically starts the animation. |
keyframes | Array | object | An array of keyframe objects, or a keyframe object whose property are arrays of values to iterate over. See basic usage for more details. | |
animationOptions | number | object | An integer representing the animation's duration (in milliseconds), or an object containing one or more timing properties. See basic usage for more details. | |
onReady | function | It's invoked when an animation is ready to play. You can access the playState, animate and animation from the event object. | |
onUpdate | function | It's invoked when an animation enters the running state or changes state. You can access the playState, animate and animation from the event object. | |
onFinish | function | It's invoked when an animation enters the finished state. You can access the playState, animate and animation from the event object. |
Use Polyfill
Web Animations API has good support amongst browsers, but it's not universal. You'll need to polyfill browsers that don't support it. Polyfills is something you should do consciously at the application level. Therefore use-web-animations
doesn't include it.
Install web-animations-js:
$ yarn add web-animations-js
# or
$ npm install --save web-animations-js
Then import it at your app's entry point:
import "web-animations-js/web-animations.min";
You can read the document for more information.
Articles / Blog Posts
ð¡ If you have written any blog post or article about
use-web-animations
, please open a PR to add it here.
- Featured on React Status #196.
- Featured on JavaScript Weekly #496.
- Featured on React Newsletter #218.
Contributors â¨
Thanks goes to these wonderful people (emoji key):
Welly ð» ð ð§ |
This project follows the all-contributors specification. Contributions of any kind welcome!
Top Related Projects
Open source, production-ready animation and gesture library for React
A zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with React, Vue, or any other JavaScript application.
JavaScript animation engine
GSAP (GreenSock Animation Platform), a JavaScript animation library for the modern web
Animate on scroll library
🍿 A cross-browser library of CSS animations. As easy to use as an easy thing.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot