Framer Motion provides a lot of powerful tools that require minimum effort to use. I've used it for a couple of years now both in my professional work and also a lot in my hobby projects. I recently got to implement some layout animations at work, and I found it fascinating how easy it was to achieve so much with so little code. So I thought it would make a great blog post!
In this post we will focus on one of Framer Motions many powerful features - the layout
prop. We will learn about how we can use it to achieve smooth layout animations with ease.
What is layout animations, and why do I need them?
Layout animations can be a great when you have an application UI where your components may be removed, switched places, added or resized. Without any animation your components will just show up in their own positions without any indication of where they came from, or where they are going. This might confuse users as to what actually happening. Layout animations can be used to guide the users attention to what is happening to the elements.
When we talk about layout animations we are referring to changes to any of the following properties:
- Positions -
grid
,flex
orposition
- Size properties -
width
orheight
- Position of elements - adding / removing an item from a list of items
Layout animation basics
With Framer Motion we can animate any motion
component between different layouts by applying the layout
prop to the element. Now the element will automatically animate to any layout changes resulting from any re-renders.
Some practical examples of when this would be happning:
- Adding / removing items in a list of items
- The
width
of an item changing due to some additional data being added / removed - The sorting of a list is reversed and we change
flex-start
toflex-end
Let's take a look at a basic example where we can change the justify-self
property on a simple square div.
1import React from 'react';2import { motion } from 'framer-motion';34type Props = {5 position: 'start' | 'center' | 'end'6}78const PositionExample: React.FC<Props> = ({ position }) => (9 <div10 style={{ justifySelf: position }}11 />12);1314export default PositionExample;
This is how easy it is to get started with layout animations using Framer Motion. The only thing we really needed to do was to add the layout
prop the the motion element and we get this smooth transition between different positions.
By adding this kind of animation to your UI you can help your user to follow what is happening on the screen and make elements move around more naturally.
Next we will take a look at another example that might be more similiar to something you'd might encouter in your own applications. We are going to look at a simple list component and see how we can leverage layout animations to help the user understand the actions taken when interacting with the list.
We will also introduce the AnimatePresence
component from Framer Motion. AnimatePresence
allows us to animate an unmounting component, so when we remove it from the list we can give it a nice "fade out" effect.
- Apples ๐
- Bread ๐ฅ
- Cheese ๐ง
- Eggs ๐ฅ
- Cookies ๐ช
1import React from 'react';2import { motion, AnimatePresence } from 'framer-motion';34const INITIAL_STATE = [5 'Apples ๐',6 'Bread ๐ฅ',7 'Cheese ๐ง',8 'Eggs ๐ฅ',9 'Cookies ๐ช',10 ];1112const SimpleList: React.FC = () => {13 const [items, setItems] = React.useState(INITIAL_STATE);1415 const onClickItem = (task: string) => {16 setItems(items.filter((item) => item !== task));17 };1819 const onClickRefresh = () => {20 setItems(INITIAL_STATE);21 };2223 return (24 <ul>25 <AnimatePresence>26 {items.map((item) => (27 <motion.li28 key={item}29 onClick={() => onClickItem(item)}30 layout31 exit={{ opacity: 0 }}32 >33 {item}34 </motion.li>35 ))}36 </AnimatePresence>37 </ul>38 );39 };4041 export default SimpleList;
That was a little more code than the previous example! However in terms of code related to animations, we did not actually add that much. Let's try and break it down.
- We wrapped out list elements in an
AnimatePresence
component. This allows us to access theexit
prop on the motion element. Theexit
prop is what we use to animate when a component is unmounting. Giving it a value ofopacity: 0
will create the fade-out effect when we remove an item from the list. - We are still using the
layout
prop on the motion elements. This is what allows each list item to smoothly transition to it's new position after an item is removed from the list.
Diving deeper into the layout prop
Now we know how we can use the layout
prop to enable smooth transitions for layout animations. But in some more advanced use-cases you might find that your content will look distorted or squished during the animation transition.
Let's take a look at a real world example of this happening. Let's imagine we have a couple of <Badge />
components that acts as some type of filters on a shopping website.
- Label 1
- Label 2
- Label 3
1import React from 'react';2import { motion } from 'framer-motion';34const BadgesExample: React.FC = () => (5 <ul>6 {filters.map((filter) => (7 <motion.li key={filter} style={{ width: '100%' }} layout>8 <Badge>9 <div10 style={{11 width: '100%',12 display: 'flex',13 alignItems: 'center',14 }}15 >16 <CloseButton />17 <span>{filter}</span>18 </div>19 </Badge>20 </motion.li>21 ))}22 </ul>23);2425export default BadgesExample;
What happens is that when we remove a Badge from the list will change the size of each Badge, so when we only use layout=true
we are telling Framer Motion to animate both the size and the position of the element. This is not always what you want. Luckily we can tell the component explicitly that we only want to animate the position of the component.
Conclusion
We have now learned the basics of how to use the layout
prop to achieve smooth layout animations for our components. Although this might have been a basic introduction, I hope it may serve as a helper to get you interested in diving deeper into Framer Motion and all the things you can do with the library! ๐
Looking for more?
If I have sparked your interest for Framer Motion and wondering what else is possible, make sure to check out their documentation. Also, make sure to check out this really cool example of how to achieve this "drag to re-order" tabs component! Super cool stuff!