Sometimes, when adding animations to your website or app, you want the animations to go into different directions depending on the context. For example, when navigating between screens, you might want the current screen to slide out to the left and the new screen to slide in from the right. But when you go back, animations should be reversed: the current screen slides out to the right and the new screen slides from the left. Take a look at this example:
My imaginary spice shop
Even though you navigate back (and in western cultures, it's associated with the left side), the product list comes from the right side.
A more radical example is the carousel, where you absolutely need to change enter/exit animations depending on the direction the user is going.
Zephyr Zest
$3.99
A fragrant blend of rare mountain herbs, perfect for adding a light, airy touch to salads and pastas.
This feels wrong!
So how do we fix this? Let's continue with the navigation example. It looks like this:
Here, both ProductDetails and ProductsList are motion.div with predefined animations:
This adds an enter and exit animation to each screen, but the problem is that it's always in one direction. To solve this, you might be tempted to just pass direction as a prop and change the transition based on it, just like this:
That kinda works, but only for enter animations. When a component is unmounted, it doesn't receive new props. It's kept on the page by Framer Motion, but for React it's already gone. So even if the direction changes, the exiting component will use the older value, which it received on the previous render.
To solve this, we need to pass direction using Framer Motion instead of props. This way, our component will be able to get the latest value for direction, even if it's already unmounted. To do this, we need to define our variants not as static values, but as functions that accept the argument custom.
And then add custom prop to our pages.
This will ensure the correct direction for enter animations. To fix exit animations, we also need to pass custom to AnimatePresence.
Since AnimatePresence is always present in the tree, it will always have the latest (and correct) version of custom which it will pass (and overwrite value from component's props) to any unmounting component.
Interactive demo:
My imaginary spice shop
The way of calculating the correct direction will depend on the structure of your app. In the example above, it's relatively easy; for carousels, it would look like this:
Interactive demo:
Zephyr Zest
$3.99
A fragrant blend of rare mountain herbs, perfect for adding a light, airy touch to salads and pastas.
We can make this code a bit cleaner by using context to pass direction around and a custom hook to group all animation-related props.
Usage:
Published at 4 February 2024
Was this interesting or useful?
I publish a newsletter with articles I found interesting and announces of my new posts. You can leave your email and get new issues delivered to your inbox!
Alternatively you can subscribe to my RSS feed to know about new posts.
Or follow me on Twitter, where I sometimes post about new articles, my pet projects, and web dev in general.
If you really like the article, you can give me monies, and I'll buy myself tasty coffee to write even more.