With naturally fluid animations you will elevate your UI & interactions. Bringing your apps to life has never been simpler.

npm i @react-spring/web

Get started

Why Springs?

We think of animation in terms of time and curves, but that causes most of the struggle we face when trying to make elements on the screen move naturally, because nothing in the real world moves like that. Springs don’t have a defined curve or a set duration.

As Andy Matuschak (ex Apple UI-Kit developer) expressed – “Animation APIs parameterized by duration and curve are fundamentally opposed to continuous, fluid interactivity.”

Hear what our fans say

Ryan Florence
@ryanflorence
Remix Co-founder
Holy smokes. I don't think animation can get any easier in React now with React Spring. Wrapping Reach UI (https://reach.tech/ui) in your own brand and feel is going to be so easy.
Ives van Hoorne
@CompuIves
Creator of Codesandbox
Big fan of React Spring!
Alexander Prinzhorn
@Prinzhorn
Software Engineer
react-spring is insane. I haven't done a lot of animations but it's the first React library I come across that does it the correct way: not using setState to change styles but bypass React.
Josh W. Comeau
@JoshWComeau
Creator of CSS for JavaScript Developers
It's fantastic :) In my React Rally talk, I explicitly recommend it over React Motion, and all the demos use it (shout-out to @0xca0a). Will share a link to it once the talk vid is up.
Pierre Bertet
@bpierre
Software Engineer
If you like react-motion but feel like your transitions aren’t smooth, it’s because it’s exclusively using React rendering. If you like Popmotion but feel like you are limited by what you can do, it’s because it entirely skips React rendering. react-spring does both, try it 👌
//
@hshoff
Engineer at Airbnb
react-spring by @0xca0a is a lovely animation library for react
bruno lemos
@brunolemos
Software Engineer
The animation lib React Spring is so awesome! Great API (first-class support for hooks), performant (doesn't trigger a re-render) and cross-platform (web / react-native / universal). Adding animations makes the app much more fun to use.
arzafran
@arzafran
Partner at Studio Freight
this would’ve been impossible without the hard work from everyone at @pmndrs, zustand, r3f, react-spring, and obviously @clementroche_‘s incredible talent. but it was no easy task to learn all the tricks we now know.. and thinking about all the stuff we still don’t
Varun Vachhar
@winkerVSbecks
Software Engineer
So, it turns out you can mix HTML and WebGL. And with react-spring you can animate both.
Alex Stanislawski
@bobylito
Software Engineer
The game being game, I have a lot of animations. I started using what is proposed by tailwind but it is not good enough for 2020. I ended moving to react spring. The learning curve is steeper than what I had expect. But it's a delightful experience afterwards.

But wait, there’s more

It’s not just for web

Choose from our five targets:

  • web
  • native
  • three
  • konva
  • zdog

Missing a target you want? Request we add it or create it yourself with our advanced API usage.

Learn more about targets
import { animated, useSpring } from '@react-spring/web'
export const MyComponent = () => {
const { x } = useSpring({
from: {
x: 0,
},
to: {
x: 1,
},
})
return <animated.div style={{ x }} />
}

Avoid unnecessary overhead

Run animations without re-rendering

Use our imperative API methods to run animations without updating state. Respond to events without the react rendering overhead to achieve smooth, fluid animation.

View imperative API

Designed with you in mind

Production ready with SSR support

Forget about useRef & useEffect to attach your animations to dom nodes. animated takes care of it for you.


Fully written in Typescript for easy integration to your pre-existing codebase.


Use a target for a small bundle size or omit the target and just use the core for an even smaller package.

55.1kb

react-spring

19.2kb

web

15.2kb

core

Wow, that's a lot!

And there's even more

  • Animate any value – strings, numbers, css variables...
  • Shorthand transformation styles
  • Interpolate values inline
  • Easily react to animation events
  • Usable with any component library
Get started now
import * as Dialog from '@radix-ui/react-dialog'
import { styled } from '@stitches/react'
import { animated, useSpring } from '@react-spring/web'
export const AnimatedDialog = ({ isOpen, onOpenCallback }) => {
const { x, backgroundColor, o } = useSpring({
x: isOpen ? '0%' : '-100%',
backgroundColor: isOpen
? 'var(--color-whiteblur)'
: 'var(--colors-white00)',
o: isOpen ? 1 : 0,
onRest: () => {
if (isOpen && onOpenCallback) {
onOpenCallback()
}
},
})
return (
<Dialog.Root>
<Overlay style={{ backgroundColor }} />
<Modal style={{ x, backgroundColor: o.to(o => 'rgba(255,255,255,' + o + ')'), }} />
</Dialog.Root>
)
}
import * as Dialog from '@radix-ui/react-dialog'
import { styled } from '@stitches/react'
import { animated, useSpring } from '@react-spring/web'
export const AnimatedDialog = ({ isOpen, onOpenCallback }) => {
const { x, backgroundColor, o } = useSpring({
x: isOpen ? '0%' : '-100%',
backgroundColor: isOpen
? 'var(--color-whiteblur)'
: 'var(--colors-white00)',
o: isOpen ? 1 : 0,
onRest: () => {
if (isOpen && onOpenCallback) {
onOpenCallback()
}
},
})
return (
<Dialog.Root>
<Overlay style={{ backgroundColor }} />
<Modal style={{ x, backgroundColor: o.to(o => 'rgba(255,255,255,' + o + ')'), }} />
</Dialog.Root>
)
}
import * as Dialog from '@radix-ui/react-dialog'
import { styled } from '@stitches/react'
import { animated, useSpring } from '@react-spring/web'
export const AnimatedDialog = ({ isOpen, onOpenCallback }) => {
const { x, backgroundColor, o } = useSpring({
x: isOpen ? '0%' : '-100%',
backgroundColor: isOpen
? 'var(--color-whiteblur)'
: 'var(--colors-white00)',
o: isOpen ? 1 : 0,
onRest: () => {
if (isOpen && onOpenCallback) {
onOpenCallback()
}
},
})
return (
<Dialog.Root>
<Overlay style={{ backgroundColor }} />
<Modal style={{ x, backgroundColor: o.to(o => 'rgba(255,255,255,' + o + ')'), }} />
</Dialog.Root>
)
}
import * as Dialog from '@radix-ui/react-dialog'
import { styled } from '@stitches/react'
import { animated, useSpring } from '@react-spring/web'
export const AnimatedDialog = ({ isOpen, onOpenCallback }) => {
const { x, backgroundColor, o } = useSpring({
x: isOpen ? '0%' : '-100%',
backgroundColor: isOpen
? 'var(--color-whiteblur)'
: 'var(--colors-white00)',
o: isOpen ? 1 : 0,
onRest: () => {
if (isOpen && onOpenCallback) {
onOpenCallback()
}
},
})
return (
<Dialog.Root>
<Overlay style={{ backgroundColor }} />
<Modal style={{ x, backgroundColor: o.to(o => 'rgba(255,255,255,' + o + ')'), }} />
</Dialog.Root>
)
}
import * as Dialog from '@radix-ui/react-dialog'
import { styled } from '@stitches/react'
import { animated, useSpring } from '@react-spring/web'
export const AnimatedDialog = ({ isOpen, onOpenCallback }) => {
const { x, backgroundColor, o } = useSpring({
x: isOpen ? '0%' : '-100%',
backgroundColor: isOpen
? 'var(--color-whiteblur)'
: 'var(--colors-white00)',
o: isOpen ? 1 : 0,
onRest: () => {
if (isOpen && onOpenCallback) {
onOpenCallback()
}
},
})
return (
<Dialog.Root>
<Overlay style={{ backgroundColor }} />
<Modal style={{ x, backgroundColor: o.to(o => 'rgba(255,255,255,' + o + ')'), }} />
</Dialog.Root>
)
}

Join our community

Share thoughts and join in with active discussions

Check out the ecosystem

See more fantastic tools from Poimandres