Presence

Contents

  1. Usage
  2. Props

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.

Have you seen Motion DevTools?

It's an incredible new developer tool for Chrome that let you inspect, edit and export Motion One and CSS animations. Animate like the good-ol' days of Flash!