Edit Page

#AnimatePresence

Animate components as they're removed from the React tree.

Wrapping one or more motion components in AnimatePresence enables the use of an exit prop, which can define an animation to use when a component is unmounted.

It can also be used to suppress initial animations on components that are present when AnimatePresence first mounts.

import { motion, AnimatePresence } from "framer-motion"

export const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)

#Usage

#Unmount animations

AnimatePresence allows components to animate out when they're removed from the React tree.

The reason a seperate component is required for this is that React lacks a lifecycle method that:

  1. Notifies components when they're going to be unmounted and
  2. Allows them to defer that unmounting until after an operation is complete (for instance an animation).

Wrap one or more motion components with AnimatePresence. This enables the use of an exit prop, which can define a state for the component to animate to before it's unmounted from the DOM.

Note: Child motion components must each have a unique key prop so AnimatePresence can track their presence in the tree.

const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <motion.div
        key="modal"
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)

Like initial and animate, exit can be defined either as a TargetAndTransition object of values, or a variant label to animate out a whole tree.

In React, changing a component's key makes React treat it as an entirely new component. So the old one is unmounted before the new one is mounted. So by changing the key of a single child of AnimatePresence, we can easily make components like slideshows.

Open example in CodeSandbox
export const Slideshow = ({ image }) => (
  <AnimatePresence>
    <motion.img
      key={image.src}
      src={image.src}
      initial={{ x: 300, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      exit={{ x: -300, opacity: 0 }}
    />
  </AnimatePresence>
)

#Multiple children

AnimatePresence works the same way with multiple children. Just ensure that each has a unique key and components will animate in and out as they're added or removed from the tree.

export const Notifications = ({ messages }) => (
  <AnimatePresence>
    {messages.map(({ id, content }) => (
      <motion.li
        key={id}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      >
        {content}
      </motion.li>
    ))}
  </AnimatePresence>
)

Add a positionTransition prop to the child components to allow them to smoothly animate into their new positions when an item is removed.

<motion.li positionTransition exit={{ opacity: 0 }} />

#Suppressing initial animations

Mount animations are already handled by motion components via the initial and animate props.

If a motion component is set to initial={false}, it'll start in the state defined in animate. But sometimes, for instance a chatbox or a slideshow, we only want to animate in new components, that are added after the initial render.

By setting initial={false} on AnimatePresence, components present when AnimatePresence first loads will start in their animate state. Only components that enter after this initial render will animate in.

const MyComponent = ({ isVisible }) => (
  <AnimatePresence initial={false}>
    {isVisible && (
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)

#Animating custom components

The children of AnimatePresence can also be custom components. The only requirement is that the first motion component within the custom component has an exit property defined.

const Item = () => (
  <div>
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  </div>
)

export const MyComponent = ({ items }) => (
  <AnimatePresence>
    {items.map(({ id }) => (
      <Item key={id} />
    ))}
  </AnimatePresence>
)

#Props

#initial: boolean

By passing initial={false}, AnimatePresence will disable any initial animations on children that are present when the component is first rendered.

<AnimatePresence initial={false}>
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

#custom: any

When a component is removed, there's no longer a chance to update its props. So if a component's exit prop is defined as a dynamic variant and you want to pass a new custom prop, you can do so via AnimatePresence. This will ensure all leaving components animate using the latest data.

#exitBeforeEnter: booleanBeta

If set to true, AnimatePresence will only render one component at a time. The exiting component will finished its exit animation before the entering component is rendered.

const MyComponent = ({ currentItem }) => (
  <AnimatePresence exitBeforeEnter>
    <motion.div key={currentItem} exit={{ opacity: 0 }} />
  </AnimatePresence>
)

#onExitComplete: () => void

Fires when all exiting nodes have completed animating out.