With naturally fluid animations you will elevate your UI & interactions. Bringing your apps to life has never been simpler.
npm i @react-spring/web
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
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.
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. Repsond to events without the react rendering overhead to achieve smooth, fluid animation.
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
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>)}