# Animation
How to animate in Framer Motion.Animations in Framer Motion are controlled via the motion
component's flexible animate
property.
It can be used in a number of ways, scaling to the complexity of your needs.
In this guide, we'll explore each of them.
import { motion } from "framer-motion"
export const MyComponent = () => (
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2 }}
/>
)
# Target object
For simple animations, we can set values directly on 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 set different types of animation by passing a Transition
to the transition
prop.
<motion.div
animate={{ x: 100 }}
transition={{ ease: "easeOut", duration: 2 }}
/>
# Mount animations
When a component mounts, 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 use the value in animate
as the component's mounted state to disable mount animations.
<motion.div animate={{ x: 100 }} initial={false} />
This will also work with server-side rendering.
# Keyframes
Values in animate
can also be set as a series of keyframes. This will animate through each value in sequence.
<motion.div
animate={{ stdDeviation: [0, 5, 0] }}
/>
By default, a keyframes animation will start with the first item in the array. To use the current value instead, null
can be passed as a placeholder. This way, if a keyframes animation starts while the value is currently animating, the transition will be more natural.
<motion.circle cx={500} animate={{ cx: [null, 100] }} />
Each of these keyframes will be spaced equidistantly throughout the animation, but you can override this by setting a times
prop on the transition
prop.
This is an array of the same length as the animation target with numbers between 0
and 1
that define when 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] }}
/>
# Variants
Target objects are 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 target objects.
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 set an animation target.
<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. These changes in variant will flow down 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}
/>
))
# Component animation controls
Declarative animations are ideal for most UI interactions. But sometimes we need to orchestrate more complex sequences.
The useAnimation
hook can be used to create a set of imperative AnimationControls
with a start
and stop
method. These controls can be passed to one or more motion
components via the animate
prop.
const MyComponent = () => {
const controls = useAnimation()
return <motion.div animate={controls} />
}
# Starting an animation
Animations can be started with the controls.start
method.
controls.start({
x: "100%",
backgroundColor: "#f00",
transition: { duration: 3 },
})
start
accepts either a TargetAndTransition
or, if the component(s) it's provided to has a variants
property set, a variant label.
controls.start("hidden")
# Sequencing
start
returns a Promise
, so it can be used to sequence animations using await
or then
.
Different controls can be sequenced together, and these sequences can be composed into functions that themselves can then be sequenced.
const sequence = async () => {
await menuControls.start({ x: 0 })
return await itemControls.start({ opacity: 1 })
}
# Dynamic start
start
can also accept a function that can dynamically start each component and the controls are bound to with a different animation definition.
Custom data can be sent to this function via the component's custom
prop.
const controls = useAnimation()
useEffect(() => {
controls.start(i => ({
opacity: 0,
x: 100,
transition: { delay: i * 0.3 },
}))
}, [])
return (
<ul>
<motion.li custom={0} animate={controls} />
<motion.li custom={1} animate={controls} />
<motion.li custom={2} animate={controls} />
</ul>
)
# Animate single values
It's also possible to imperatively animate single values or a single MotionValue
with the low-level animate
function.
This function is for advanced use-cases where you want to animate a MotionValue
without binding it to a component, or by using animate
's onUpdate
method to modify the animated value in some way.
# animate(from, to, transition): PlaybackControls
Animate a single value or a MotionValue
.
The first argument is either a MotionValue
to animate, or an initial animation value.
The second is either a value to animate to, or an array of keyframes to animate through.
The third argument can be either tween or spring options, and optional lifecycle methods: onUpdate
, onPlay
, onComplete
, onRepeat
and onStop
.
Returns PlaybackControls
, currently just a stop
method.
const x = useMotionValue(0)
useEffect(() => {
const controls = animate(x, 100, {
type: "spring",
stiffness: 2000,
onComplete: v => {}
})
return controls.stop
})
from: MotionValue<V> | V |
---|
to: V | V[] |
transition: AnimationOptions<V> |
returns: PlaybackControls |
# Layout animations
A motion
component can automatically animate between different layouts that occur as result of a re-render by setting the layout
prop to true
.
<motion.div layout />
Any layout change will be animated. That could be any combination of:
- Reordering of a list.
- A style set on the component itself, for example a change in
width
orposition
. - A change in the parent's layout, e.g. flexbox or grid.
- Or any other change in the component's layout.
For example, this component is animated by switching justify-content
between flex-start
and flex-end
:
# Scale correction
All layout animations are performed using the transform
property, resulting in smooth framerates.
Animating layout using transforms can sometimes visually distort children. To correct this distortion, the first child elements of the element can also be given layout
property:
<motion.div layout>
<motion.div layout />
</motion.div>
Transforms can also distort boxShadow
and borderRadius
. The motion
component will automatically correct this distortion on both props, as long as they're set as motion values.
If you're not animating these values, the easiest way to do this is to set them via initial
.
<motion.div initial={{ borderRadius: 20 }} />
# Customising layout animations
Layout animations can be customised using the transition
property.
<motion.div layout transition={{ duration: 0.3 }} />
Each axis can be animated seperately by naming layoutX
and layoutY
transitions.
Currently, layoutX
and layoutY
will animate the position and size of an axis simultaneously. In a future release it'll be possible to configure these separately.
<motion.div
layout
transition={{
layoutX: { duration: 0.3 },
layoutY: { delay: 0.2, duration: 0.3 },
}}
/>
# Troubleshooting
# The component's layout isn't animating
Ensure the component is set to display: block
or display: inline-block
, as transform
has no effect on display: inline
components.
# SVG layout animations are broken
SVG components aren't currently supported with layout animations. This will be fixed in a future release.
# Rotation and skew transforms aren't taking effect
rotate
and skew
transforms are not currently compatible with layout animations.
# Shared layout animations
Wrapping components with the AnimateSharedLayout
component enables you to perform layout animations:
- Synced across a set of components that don't otherwise share state.
- Between different components with a common
layoutId
as they're added/removed.
import { AnimateSharedLayout } from "framer-motion"
When one layout
component in an AnimateSharedLayout
changes layout, all other layout
components check their own layouts and animate accordingly.
function List({ items, selectedId }) {
/**
* Local state changes in Item that affect layout will
* also affect the parent motion.ul
*/
return (
<AnimateSharedLayout>
<motion.ul layout>
{items.map(item => (
<Item {...item} />
))}
</motion.ul>
</AnimateSharedLayout>
)
}
When a component with a layoutId
prop is removed from one part of the tree and a new component with the same layoutId
is added elsewhere, the new component will automatically animate from the old component's position.
function List({ items, selectedId }) {
return (
<AnimateSharedLayout>
{items.map(item => (
<li>
{item.title}
{item.id === selectedId && (
<motion.div layoutId="underline" />
)}
</li>
))}
</AnimateSharedLayout>
)
}
The new component will also automatically inherit the current state of any animating values on the old component, and animate from those on entry.
<motion.div
layoutId="underline"
animate={{ backgroundColor: item.color }}
/>
All AnimateSharedLayout
options can be found in the AnimateSharedLayout
docs.