Documentation

Documentation

React

AnimatePresence

AnimatePresence

AnimatePresence makes exit animations easy. By wrapping one or more motion components with AnimatePresence, we gain access to the exit animation prop.

<AnimatePresence>
  {show && <motion.div key="modal" exit={{ opacity: 0 }} />}
</AnimatePresence>

Usage

Import

import { AnimatePresence } from "motion/react"

Exit animations

AnimatePresence works by detecting when its direct children are removed from the React tree.

This can be due to a component mounting/remounting:

<AnimatePresence>
  {show && <Modal key="modal" />}
</AnimatePresence>

Its key changing:

<AnimatePresence>
  <Slide key={activeItem.id} />
</AnimatePresence>

Or when children in a list are added/removed:

<AnimatePresence>
  {items.map(item => (
    <motion.li key={item.id} exit={{ opacity: 1 }} layout />
  ))}
</AnimatePresence>

Any motion components within the exiting component will fire animations defined on their exit props before the component is removed from the DOM.

function Slide({ img, description }) {
  return (
    <motion.div exit={{ opacity: 0 }}>
      <img src={img.src} />
      <motion.p exit={{ y: 10 }}>{description}</motion.p>
    </motion.div>
  )
}

Note: Direct children must each have a unique key prop so AnimatePresence can track their presence in the tree.

Like initial and animate, exit can be defined either as an object of values, or as a variant label.

const modalVariants = {
  visible: { opacity: 1, transition: { when: "beforeChildren" } },
  hidden: { opacity: 0, transition: { when: "afterChildren" } }
}

function Modal({ children }) {
  return (
    <motion.div initial="hidden" animate="visible" exit="hidden">
      {children}
    </motion.div>
  )
}

Changing key

Changing a key prop makes React create an entirely new component. So by changing the key of a single child of AnimatePresence, we can easily make components like slideshows.

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>
)

Accessing presence state

When a component is the child of AnimatePresence, it can use usePresence to access information about whether it's still present in the React tree.

If isPresent is false, it means that a component has been removed the tree, but AnimatePresence won't remove it until safeToRemove has been called.

import { usePresence } from "motion/react"

export const Component = () => {
  const [isPresent, safeToRemove] = usePresence()

  useEffect(() => {
    !isPresent && setTimeout(safeToRemove, 1000)
  }, [isPresent])

  return <div />
}

This allows you to do anything you like with AnimatePresence and its presence state, not just perform animations.

Props

initial

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

<AnimatePresence initial={false}>
  <Slide key={activeItem.id} />
</AnimatePresence>

custom

When a component is removed, there's no longer a chance to update its props (because it's no longer in the React tree). Therefore we can't update its exit animation with the same render that removed the component.

By passing a value through AnimatePresence's custom prop, we can use dynamic variants to change the exit animation.

const variants = {
  hidden: (direction) => ({
    opacity: 0,
    x: direction === 1 ? -300 : 300
  }),
  visible: { opacity: 1, x: 0 }
}

export const Slideshow = ({ image, direction }) => (
  <AnimatePresence custom={direction}>
    <motion.img
      key={image.src}
      src={image.src}
      variants={variants}
      initial="hidden"
      animate="visible"
      exit="hidden"
    />
  </AnimatePresence>
)

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. Note: Currently only renders a single child at a time.

  • "popLayout": Exiting children will be "popped" out of the page layout. This allows surrounding elements to move to their new layout immediately.

Custom component note: When using popLayout mode, any immediate child of AnimatePresence that's a custom component must be wrapped in React's forwardRef function, forwarding the provided ref to the DOM node you wish to pop out of the layout.

onExitComplete

Fires when all exiting nodes have completed animating out.

A Motion+ membership will give you early access to features & content, access to our private Github and Discord, and more.

It's a one-time fee that grants lifetime access. No subscription necessary!

MOTION+

Introducing Cursor

Cursor is a creative cursor component for React, that makes it super easy to make custom cursor and follow cursor effects.


Hover over these examples to check out some of what it can do:

Custom cursor

Follow with spring

Multicursor

?

?