Animate Presence

Animate components when they're removed from the Vue tree.

The AnimatePresence component enables you to animate components as they enter and exit the Vue tree when controlled by v-if or v-show directives.

Import

import { AnimatePresence } from 'motion-v'

Usage

<script setup lang="ts">
import { AnimatePresence, Motion } from 'motion-v'
import { ref } from 'vue'

const show = ref(true)
</script>

<template>
  <div class="flex flex-col items-center gap-4 w-full">
    <Button @click="show = !show">
      {{ show ? 'hide' : 'show' }}
    </Button>
    <div class="w-1/3">
      <AnimatePresence>
        <Motion
          v-show="show"
          class="bg-primary  aspect-square rounded-2xl"
          :initial="{ scale: 0 }"
          :animate="{ rotate: 180, scale: 1 }"
          :exit="{ rotate: 0, scale: 0 }"
        />
      </AnimatePresence>
    </div>
  </div>
</template>

Multiple

<script setup lang="ts">
import { AnimatePresence, Motion } from 'motion-v'
import { ref } from 'vue'

const show = ref(true)
</script>

<template>
  <div class="flex flex-col items-center gap-4 w-full">
    <button @click="show = !show">
      {{ show ? 'hide' : 'show' }}
    </button>
    <AnimatePresence
      multiple
      as="div"
      class="flex gap-4 w-40"
    >
      <Motion
        v-show="show"
        key="1"
        class="bg-primary w-1/3  aspect-square rounded-2xl flex-1"
        :initial="{ scale: 0 }"
        :animate="{ rotate: 180, scale: 1 }"
        :exit="{ rotate: 0, scale: 0 }"
      />
      <Motion
        v-if="show"
        key="2"
        class="bg-primary  aspect-square rounded-2xl flex-1"
        :initial="{ scale: 0 }"
        :animate="{ rotate: 180, scale: 1 }"
        :exit="{ rotate: 0, scale: 0 }"
      />
    </AnimatePresence>
  </div>
</template>

Props

multiple

  • Default: false

AnimatePresence is based on TransitionGroup and Transition, when multiple is true, it will use TransitionGroup to animate multiple children.

mode

  • Default: sync

Decides how AnimatePresence handles entering and exiting children.

  • sync: Children animate in/out as soon as they're added/removed.
  • wait: The entering child will wait until the exiting child has animated out.
  • popLayout: Exiting children will be "popped" out of the page layout. This allows surrounding elements to move to their new layout immediately.
<script setup lang="ts">
import { ref } from 'vue'
import { AnimatePresence, Motion } from 'motion-v'

const count = ref(0)
const items = ref([0])
const popLayout = ref(false)
function removeItem<T>(arr: T[], item: T) {
  const index = arr.indexOf(item)
  if (index > -1)
    arr.splice(index, 1)
}

function addItem() {
  count.value++
  items.value = [...items.value, count.value]
}

function removeItemById(id: any) {
  const newItems = [...items.value]
  removeItem(newItems, id)
  items.value = newItems
}
</script>

<template>
  <div class="flex flex-col items-center">
    <div class="flex flex-col items-center pb-[50px]">
      <label class="flex items-center my-5">
        <code class="font-mono">popLayout</code>
        <input
          v-model="popLayout"
          type="checkbox"
          class="accent-pink-500"
        >
      </label>
      <Motion
        as="button"
        :initial="{ scale: 1 }"
        :while-tap="{ scale: 0.95 }"
        class="w-[150px] px-6 py-4 text-lg font-bold text-white bg-pink-500 rounded-full cursor-pointer"
        @click="addItem"
      >
        Add item
      </Motion>
    </div>
    <AnimatePresence
      class="flex flex-col w-[300px] h-[300px] gap-5 p-0 list-none"
      :mode="popLayout ? 'popLayout' : 'wait'"
      multiple
      as="ul"
    >
      <Motion
        v-for="id in items"
        :key="id"
        :data-key="id"
        as="li"
        :animate="{ scale: 1, opacity: 1 }"
        :exit="{
          scale: 0.8,
          opacity: 0,
          transition: {
            duration: 0.5,
          },
        }"
        :transition="{
          type: 'spring',
        }"
        :layout="true"
        class="block h-20 flex-[0_0_80px] bg-pink-500 rounded-[20px] p-0 m-0 list-none"
        @click="removeItemById(id)"
      />
    </AnimatePresence>
  </div>
</template>

<style>
</style>