Motion
Back to framer.com
DocumentationAnimation
Overview
Motion
Back to framer.com
Design and publish your first free site today.
Getting started
  • Introduction
  • Examples
Animation
  • Overview
  • Layout
  • Gestures
  • Scroll
  • Transition
Components
  • motion
  • AnimatePresence
  • LayoutGroup
  • LazyMotion
  • MotionConfig
  • Reorder
Motion values
  • Overview
  • useMotionValueEvent
  • useMotionTemplate
  • useScroll
  • useSpring
  • useTime
  • useTransform
  • useVelocity
  • useWillChange
Hooks
  • useAnimate
  • useAnimationFrame
  • useDragControls
  • useInView
  • useReducedMotion
Universal
  • animate
  • transform
  • stagger
  • Easing functions
3D
  • Introduction
  • LayoutCamera
  • LayoutOrthographicCamera
  • MotionCanvas
Guides
  • Accessibility
  • Reduce bundle size
  • Upgrade guides
Community
  • GitHub
  • Discord

Animation

How to animate in Framer Motion.

There are multiple ways to animate in Framer Motion, scaling to the complexity of your needs.

#Simple animations

Most animations will be performed with the motion component and the animate prop.

<motion.div animate={{ x: 100 }} />

When any value in animate changes, the component will automatically animate to the updated target.

#Transitions

By default, Motion will create an appropriate animation for a snappy transition based on the types of value being animated. For instance, physical properties like x or scale will be animated via a spring simulation. Whereas values like opacity or color will be animated with a tween.

However, you can define different types of animation by passing a default transition to the transition prop.

<motion.div
animate={{ x: 100 }}
transition={{ ease: "easeOut", duration: 2 }}
/>

#Enter animations

When a motion component is first created, it'll automatically animate to the values in animate if they're different from those defined in style or initial. You can set the initial prop to false to disable enter animations.

<motion.div animate={{ x: 100 }} initial={false} />

#Exit animations

In React, when a component is removed from the tree, it's removed instantly. Framer Motion provides the AnimatePresence component to keep components in the DOM while they perform an exit animation.

<AnimatePresence>
{isVisible && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
)}
</AnimatePresence>

#Keyframes

Values in animate can also be set as a series of keyframes. This will animate through each value in sequence.

<motion.div
animate={{ x: [0, 100, 0] }}
/>

We can use the current value as the initial keyframe by passing a wildcard keyframe, null.

<motion.div
animate={{ x: [null, 100, 0] }}
/>

This way, if a keyframes animation starts while the value is currently animating, the transition will be more natural. It also reduces duplication in our code.

<motion.circle cx={500} animate={{ cx: [null, 100] }} />

Each keyframe will be spaced evenly throughout the animaton. You can override this by setting the times option via transition.

times is an array of the same length as the keyframes array, with numbers between 0 and 1 definining where in the animation each keyframe should be hit.

<motion.circle
cx={500}
animate={{ cx: [null, 100, 200] }}
transition={{ duration: 3, times: [0, 0.2, 1] }}
/>

#Gesture animations

Framer Motion has shortcuts for animating to a set of values when gestures start, like hover, tap, drag, focus and inView:

<motion.button
initial={{ opacity: 0.6 }}
whileHover={{
scale: 1.2,
transition: { duration: 1 },
}}
whileTap={{ scale: 0.9 }}
whileInView={{ opacity: 1 }}
/>

It'll automatically figure out which values to animate back to when these gestures end.

#Variants

Setting animate as an object is useful for simple, single-component animations. But sometimes we want to create animations that propagate throughout the DOM, and orchestrate those animations in a declarative way. We can do so with variants.

Variants are sets of pre-defined targets.

const variants = {
visible: { opacity: 1 },
hidden: { opacity: 0 },
}

They're passed into motion components via the variants prop.

<motion.div variants={variants} />

These variants can be referred to by label, wherever you can define an animation object.

<motion.div
initial="hidden"
animate="visible"
variants={variants}
/>

#Propagation

If a motion component has children, changes in variant will flow down through the component hierarchy until a child component defines its own animate property.

const list = {
visible: { opacity: 1 },
hidden: { opacity: 0 },
}
const item = {
visible: { opacity: 1, x: 0 },
hidden: { opacity: 0, x: -100 },
}
return (
<motion.ul
initial="hidden"
animate="visible"
variants={list}
>
<motion.li variants={item} />
<motion.li variants={item} />
<motion.li variants={item} />
</motion.ul>
)

#Orchestration

By default, all these animations will start simultaneously. But by using variants, we gain access to extra transition props like when, delayChildren, and staggerChildren that can let parents orchestrate the execution of child animations.

const list = {
visible: {
opacity: 1,
transition: {
when: "beforeChildren",
staggerChildren: 0.3,
},
},
hidden: {
opacity: 0,
transition: {
when: "afterChildren",
},
},
}

#Dynamic variants

Each variant can be defined as a function that resolves when a variant is accessed. These variant functions are provided a single argument, which can be set in a component's custom prop.

const variants = {
visible: i => ({
opacity: 1,
transition: {
delay: i * 0.3,
},
}),
hidden: { opacity: 0 },
}
return items.map((item, i) => (
<motion.li
custom={i}
animate="visible"
variants={variants}
/>
))

#Multiple variants

Props like animate, whileHover etc can define one or more variants by passing a string or an array of strings.

<motion.ul variants={["open", "primary"]} />

If variants define the same values, variants appearing later in the array will take precedence over those earlier in the array.

#Manual controls

Declarative animations are ideal for most UI interactions. But sometimes we need to orchestrate more complex sequences.

The useAnimate hook can be used to:

  • Animate any HTML/SVG element
  • Create complex sequences of animations
  • Control animations with time, speed, play(), pause() and other playback controls.
const MyComponent = () => {
const [scope, animate] = useAnimate()
useEffect(() => {
const animation = async () => {
await animate(scope.current, { x: "100%" })
animate("li", { opacity: 1 })
}
animation()
}, [])
return (
<ul ref={scope}>
<li />
<li />
<li />
</ul>
)
}

#Animate single values

It's also possible to use useAnimate to animate single values or a single MotionValue.

const [scope, animate]= useAnimate()
const x = useMotionValue(0)
useEffect(() => {
const controls = animate(x, 100, {
type: "spring",
stiffness: 2000,
onComplete: v => {}
})
return controls.stop
})

#Animate content

We can render the current value of a MotionValue by passing it as a motion component's child.

const count = useMotionValue(0)
const rounded = useTransform(count, latest => Math.round(latest))
useEffect(() => {
const controls = animate(count, 100)
return controls.stop
}, [])
return <motion.div>{rounded}</motion.div>

#Hardware-accelerated animations

Browsers are able to run some animations via the GPU using CSS or the Web Animations API (WAAPI).

Running animations on the GPU enables smoother performance, especially in situations where the main JavaScript thread becomes busy. GPU animations are also more energy efficient, leading to lower battery usage.

However, native browser animation APIs offer fewer features than Framer Motion's JavaScript animations. For this reason, Motion's hybrid engine intelligently decides when an animation can safely run on the GPU, falling back to JavaScript animations when it needs the additional functionality.

It even does some work to ensure features that don't traditionally work on the GPU are supported, like spring animations, custom easing functions, velocity transfer and animation interruption.

#Supported values

Different browsers are capable of accelerating different values so Framer Motion supports a superset of them.

  • transform
  • opacity
  • clipPath
  • filter

Note on transform: Motion allows animating independent transforms like x and scale, while browsers don't. Therefore, hardware acceleration only works when transform itself is animated.

<motion.div
animate={{ transform: "translateX(100px)" }}
/>

The downside to this approach, as is the case with animating transform via CSS, is all transform values have to be animated together. So it is recommended to normally use independent transforms for readability and flexibility, using transform directly only in situations where you really need the accelerated animations.

#Unsupported features

Supported values will always use hardware-accelerated animations, unless:

  • The motion component has on onUpdate prop.
  • The value is passed in as a motion value via the style prop.
  • repeatDelay is set.
  • repeatType is set as "mirror".
  • damping is set to 0.

This list of opt-outs will be reduced as work on hardware-accelerated animations progresses.

PreviousExamplesNextLayout animations
On this page
  • Simple animations
  • Transitions
  • Enter animations
  • Exit animations
  • Keyframes
  • Gesture animations
  • Variants
  • Propagation
  • Orchestration
  • Dynamic variants
  • Multiple variants
  • Manual controls
  • Animate single values
  • Animate content
  • Hardware-accelerated animations
  • Supported values
  • Unsupported features

Copyright © 2022 Framer B.V.

  • Security
  • Terms of Service
  • Privacy Statement