Motion for React DOM · React Native Animated API
Write motion once. It runs smoothly, and it never breaks.
Animated brings React Native's Animated to the web. One value drives any number of elements without a React render per frame, supported motion plays in the browser itself, and every interruption continues from what is on screen.
npm install @kkwaenggwari/animatedOne clock value drives the ripple of all 64 shapes. Move your pointer over the stage.
Measured on this release
Measured with the 1.0.0 build in headless Chrome on a desktop PC. Numbers vary by device. How we measured
- 0.00msJavaScript per frame while 400 elements move
Finite transform and opacity motion on Animated elements plays in the browser. The page's own frame callbacks do no work.
- 0.13msJavaScript per frame for one value driving 10,000 elements
The value writes one CSS variable; every element derives its style from it in CSS.
- 0React renders during motion
Values never go through React state. Components render when your props change, not when a frame changes.
01 · Easy
The API you already know, on ordinary React style
timing, spring, interpolate, loop and Animated.event keep their React Native names and configs. A value goes straight into an ordinary style prop, so there is no special component to learn before your first motion.
- Port React Native code by renaming
Animated.ViewtoAnimated.div. - One value can move a bar, a dial and a row of cards at once, each with its own range.
useAnimatedowns the recipe: it starts on mount, restarts when a dependency changes and cleans up on unmount.
Preparing the example…
Same calls as React Native
// React Native
<Animated.View style={{ transform: [{ rotate }] }} />
// React DOM with @kkwaenggwari/animated — the rest is identical
<Animated.div style={{ transform: [{ rotate }] }} />
const spin = useAnimatedValue(0);
const rotate = spin.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] });
Animated.loop(
Animated.timing(spin, { toValue: 1, duration: 900, easing: Easing.linear, useNativeDriver: true }),
).start();02 · Fast
No React render per frame
A hook value is a CSS variable. Linear interpolations and arithmetic become exact calc() expressions of that variable, so each frame is one write and the browser derives the rest. Finite transform and opacity motion on Animated.<tag> elements plays in the browser without frame callbacks.
- Change the number of dots: the counter shows React rendered once per change, never per frame.
scopewrites the value once on a container instead of on every element.inspect(element)tells you which path each property uses and why.
Preparing the example…
03 · Stable
Interrupt it anywhere. It continues.
A new target starts from where the element is on screen, and a spring also keeps its velocity, so reversing mid-flight turns smoothly instead of stopping first. Controllers declared in a hook are stopped and released on replacement and unmount, and server-rendered markup keeps animating after hydration.
- Click twice quickly: with
springthe path bends, withtimingit keeps position but starts a new curve. - Stopping keeps the value where it is; nothing jumps to an end state.
- No stray frame loops after unmount, route changes or hidden tabs.
Preparing the example…
- Magnetic dockIcons grow as the pointer passes, pushing their neighbors aside, and settle when it leaves.
moveInputfollowuseAnimatedCSSmultiply - Swipe deckDrag the top card. Past the threshold it flies away; otherwise it springs back.
dragInputuseAnimatedListenerAnimated.div - Shared galleryA tile grows into a detail view and shrinks back into the grid.
Animated.SceneAnimated.Keepmove
Built on Animated
Need a finished component? Animated Chorus.
Rolling numbers, travelling tab highlights, progress, sheets and animated lists that drop straight into React and React Native. These three are running on this page right now.
Visit Animated ChorusStart in three minutes
Install the package, move your first value, then pick a guide for the job in front of you.
npm install @kkwaenggwari/animated