Basic animation
The easiest way to animate an element, is to set some values on animate
.
export function Example() {
return (
<Center>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
position: "absolute"
}}
animate={{
left: 10,
top: 10,
scale: 0.5,
rotate: 45,
backgroundColor: "#ffd700"
}}
/>
</Center>
);
}
open in CodeSandboxWhenever you give animate
new values, the motion.div
will animate to those values.
Now, this animation happens immediately, the moment the element becomes visible. But we’ll look at how you can trigger it with an event.
Obviously, there’s more code here because I’ve also had so set visual and positioning properties. So in upcoming examples, I’ll often only show the animation code, like this:
export function Example() {
return (
<Center>
<motion.div
animate={{
left: 10,
top: 10,
scale: 0.5,
rotate: 45,
backgroundColor: "#ffd700"
}}
/>
</Center>
);
}
But you can always find the complete code in the CodeSandbox.
Transform properties
Above I used the left
and top
properties to animate the div’s position, but it’s actually better to use x
and y
for this. With these, what they call, transform properties, animations will run smoother (GPU accelerated).
They also have the advantage of starting from zero, so moving an element 10 points to the right is as simple as x: 10
. Other GPU-accelerated transform properties are: scale
, scaleX
, scaleY
, rotate
, rotateX
, rotateY
, skewX
, and skewY
.
export function Example() {
return (
<motion.div
animate={{ scaleY: 0.5, scaleX: 2, skewX: -6, y: -120 }}
/>
);
}
open in CodeSandboxTransform origin
These transforms (scaling, rotating, and skewing) will happen from the element’s transformation origin. By default, this is the center, but you can change that.
Here I placed the originY
at the top of the div so that the (x-axis) rotation happens with that edge as the center point.
export function Example() {
return (
<div>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
originY: 0
}}
animate={{ rotateX: 360 }}
/>
</div>
);
}
open in CodeSandboxBy the way, I applied some perspective
to its parent div to make the animation look three-dimensional:
export function Example() {
return (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
placeItems: "center",
placeContent: "center",
perspective: 600
}}
>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
originY: 0
}}
animate={{ rotateX: 360 }}
/>
</div>
);
}
Transform origin
transform-origin
perspective
Colors
Just like you can change a div’s backgroundColor
, you can also animate it. As always, you write the color as a text string, in any of these CSS color formats:
- Hex Code — “#00ff00”
- Websafe Hex Code — “#0f0”
- RGB Decimal — “rgb(0, 255, 0)”
- RGBA Decimal — “rgba(0, 255, 0, 1)” (the last value is ‘alpha’)
- Hue Saturation Lightness — “hsl(120, 100%, 50%)”
- Hue Saturation Lightness Alpha — “hsla(120, 100%, 50%, 1)”
export function Example() {
return (
<div>
<motion.div
animate={{ backgroundColor: "#ff6347" }}
/>
<motion.div
animate={{ backgroundColor: "hsl(290, 50%, 60%)" }}
/>
<motion.div
animate={{ backgroundColor: "rgba(153, 204, 102, 0.8)" }}
/>
</div>
);
}
open in CodeSandboxYou can also animate between different color formats, like from a HEX to an RGB value.
Pro tip: You can’t animate with CSS named colors like, e.g., “Tomato”.
Supported Values
background
background-color
Complex values
Some CSS values are more complex. For example, a CSS boxShadow
is also written as a string, but this string can contain the shadow’s x- and y-offset, blur, spread, and color.
You can animate all these values simultaneously if you stick to one kind of notation. Take this example:
export function Example() {
return (
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
// Initial shadow
boxShadow: "0px -300px 80px 100px rgba(255, 255, 255, .3)"
}}
initial={{ backgroundColor: "#fff" }}
animate={{
backgroundColor: "#08f",
// Animation
boxShadow: "0px 0px 80px 30px #fff"
}}
/>
);
}
open in CodeSandboxIts initial shadow (set on style
) is:
"0px -300px 80px 100px rgba(255, 255, 255, .3)"
Which stands for:
0px
— x-offset-300px
— y-offset80px
— blur radius100px
— spread,- and
rgba(255, 255, 255, .3)
as the color.
… so I had to animate to a shadow defined with the same five values:
"0px 0px 80px 30px #fff"
Animating to a shadow written in the shorter ‘just x- and y-offset and color’ form (also possible in CSS) would not work.
"0px 0px #fff"
Supported Values, style
boxShadow
Adding state
Of course, you don’t always have to animate an element when it appears. Whatever you pass to animate
can be saved in a useState()
so that you can change it.
State: A Component’s Memory, useState()
Example 1
Here’s an additive animation. 45
is added to the degrees
state every time you tap, making the div rotate.
export function Example() {
const [degrees, setDegrees] = useState(0);
function add45() {
setDegrees(degrees + 45);
}
return (
<motion.div
animate={{ rotate: degrees }}
onTap={add45}
/>
);
}
open in CodeSandboxExample 2
In this second example, the motion div will rotate when you pan it (panning is like dragging, but without the div going anywhere 😉).
Framer Motion’s onPan()
event returns two things: a common MouseEvent (or TouchEvent) object and a special PanInfo object that contains (among other things) a delta
of points that the pointer moved since the last event.
I named that second object info
, so the distance traveled since the last time onPan()
was called will be in info.delta.x
.
Since Framer Motion 11, this doesn’t animate well, so here we’re changing rotate
directly in the <div>
’s style
.
export function Example() {
const [degrees, setDegrees] = useState(0);
return (
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
color: "#999",
fontSize: "40px",
display: "flex",
placeItems: "center",
placeContent: "center",
cursor: "ew-resize",
rotate: degrees
}}
onPan={(_, info) => setDegrees(degrees + info.delta.x)}
>
{Math.round(degrees)}
</motion.div>
);
}
open in CodeSandboxThis onPan()
event is called continuously, so delta.x
will contain small values, like 1
point, another point, -1
point when panning to the left, or often: 0
points. Every time onPan()
is called, that delta is added to the current number of degrees
with setDegrees()
. Thus, when you pan to the right, the div rotates clockwise, and when panning left, counterclockwise.
(JavaScript’s Math.round()
function converts the decimal value of degrees
to an integer.)
Multiple properties
You don’t have to create an useState()
for every property you want to animate, you can also put a set of properties in an object (here, it contains values for both scale
and rotate
).
export function Example() {
const [animate, setAnimate] = useState({ scale: 1, rotate: 0 });
return (
<motion.div
animate={animate}
onTapStart={() => setAnimate({ scale: 1.25, rotate: 90 })}
onTap={() => setAnimate({ scale: 1, rotate: 0 })}
/>
);
}
open in CodeSandboxYou probably know that an onTap()
event gets triggered when you release your finger; at the end of the tap gesture. And there’s another event that gets triggered at the beginning, when you press down: onTapStart()
.
Using useState()
purely for… state
In the previous examples, we’ve used
to animate just one property (scale
) or an object that contains multiple properties (scale
and rotate
).
But you can use useState()
to keep track of just the state. Meaning something like ”Is the switch on or off?” or, in the following example, “Is the box dragged right now?”
Here
export function Example() {
const [dragging, setDragging] = useState(false);
return (
<motion.div
animate={{ backgroundColor: dragging ? "#a0f" : "#04f" }}
transition={{ duration: 0.5 }}
>
<motion.div
drag
dragConstraints={{ top: -140, right: 140, bottom: 140, left: -140 }}
animate={{ scale: dragging ? 1 : 0.8 }}
onDragStart={() => setDragging(true)}
onDragEnd={() => setDragging(false)}
/>
</motion.div>
);
}
open in CodeSandboxThe parent’s backgroundColor
is now set inline, with a ternary operator (a concise way of writing an if…else
conditional). When dragging
is true
, it will animate to the first color (“#a0f”), and when not, it animates to the second color (“#04f”).
And the same happens with the draggable div’s scale
: when dragging
is true
, it will be 1
, and when false
, it’ll be the smaller 0.8
.
drag
, dragConstraints
, onDragStart()
, onDragEnd()
Conditional (ternary) operator, if…else
Which properties can you animate?
A bunch more properties can be animated. Check the Animatable Properties page for an overview.