Perform exit animations in Vue.
<Presence> <Motion v-show="show" :animate="{ opacity: 1 }" :exit="{ opacity: 0 }"> </Motion> </Presence>
Usage
Import Motion
from "motion/vue"
and register it with your component.
<template> <div class="container"> <Presence> <Motion v-show="show" :initial="{ opacity: 0, scale: 0 }" :animate="{ opacity: 1, scale: 1 }" :exit="{ opacity: 0, scale: 0.6 }" class="box" /> </Presence> <button @click="show = !show"> Toggle </button> </div> </template> <script> import { Motion, Presence } from "motion/vue" export default { components: { Motion, Presence }, data() { return { show: true } } } </script> <style> .container { width: 100px; height: 150px; display: flex; flex-direction: column; justify-content: flex-end; } .container button { cursor: pointer; } .box { width: 100px; height: 100px; border-radius: 10px; background-color: var(--splash); } </style>
Now, when a child Motion
component is hidden with v-if
or v-show
, it will animate to the target defined in exit
prop.
Note: Presence
currently only supports a single rendered child.
Animate between elements
By passing a different key
to multiple children and rendering just one at a time, we can animate between them at a given time.
<template> <div class="container"> <Presence> <Motion :key="current" :initial="{ opacity: 0, x: 50 }" :animate="{ opacity: 1, x: 0, transition: { delay: 0.1 } }" :exit="{ opacity: 0, x: -50 }" class="slide" > {{ current }} </Motion> </Presence> <button @click="current++"> Next </button> </div> </template> <script> import { Motion, Presence } from "motion/vue" export default { components: { Motion, Presence }, data() { return { current: 0 } } } </script> <style> .container { width: 100px; height: 150px; display: flex; flex-direction: column; justify-content: flex-end; position: relative; } .container button { cursor: pointer; } .slide { width: 100px; height: 100px; border-radius: 10px; background-color: var(--red); color: var(--white); display: flex; justify-content: center; align-items: center; font-size: 72px; line-height: 72px; font-family: Inter, sans-serif; font-weight: 700; position: absolute; top: 0; left: 0; } </style>
In the above example, each element has the position: absolute
CSS rule so when the incoming element is rendered it doesn't conflict with the element animating away.
In situations where this isn't possible, :exitBeforeEnter={true}
can be set on Presence
to ensure the exiting element animates out before the entering element is rendered.
Props
initial
Default: true
If false
, will disable the first animation on all child Motion
elements the first time Presence
is rendered.
exitBeforeEnter
Default: false
If true
, Presence
will wait for the exiting element to finish animating out before animating in the next one.