Motion: [FEATURE] motion.Fragment or similar API

Created on 22 Oct 2019  路  2Comments  路  Source: framer/motion

When animating groups of components inside of an AnimatePresence element, the docs state that "the first motion component within the custom component has an exit property defined" but I feel like this falls down in scenarios like thus:

<AnimatePresence>
    {bool && (
        <>
            <motion.div exit="exit"></motion.div>
            <motion.div exit="exit"></motion.div>
            <motion.div exit="exit"></motion.div>
        </>
)}
</AnimatePresence>

If I'm constrained by a layout that doesn't allow those divs to be wrapped in a container div (for example, these are all children of a CSS grid) then I can't easily do things like a stagger, and exit doesn't work at all because it looks like the Fragment container will just get unmounted immediately.

Even if I was in a position to use a div, I've found that sometimes I'm creating a motion.div container just to host an initial="" animate="" exit="" set of props but include no variants - just so the variant names percolate down to child motion.divs that do the actual animating.

Describe the solution you'd like

I'd like to see something like:

<motion.Fragment enter="" animate="" exit="" transition={{}}>
    {children}
</motion.Fragment>

Which allows for a Fragment that only hosts variant names and can not animate itself. I've included transition so you can pass staggerChildren and possibly other orchestration props as they come along. Maybe it could just be an orchestration props that only accepts a subset of all the transition options.

Describe alternatives you've considered
As mentioned above, I would typically try to use a wrapper div, or go without in the case of sibling exit animations.

I feel that conceptually this Fragment idea seems like a great addition to Framer Motion, and would allow for some really powerful orchestration and solve a few edges cases that I've ran into.

I'm also happy to be told if I'm way off the mark and this already exists

feature

Most helpful comment

To add to the above - if you want to do staggering via staggerChildren rather than manually incrementing the delay prop instead of motion.Fragment you could do a motion.div with style={{ display: 'contents' }

<motion.div initial="hidden" animate="visible" exit="hidden" variants={variantsWithStaggerChildren} style={{ display: "contents" }}>
  <motion.div variants={childVariants} />
  <motion.div variants={childVariants} />
  <motion.div variants={childVariants} />
</motion.div>

All 2 comments

The <AnimatePresense> is built to handle multiple elements already, triggering the exit once the element stop being rendered. Not sure what the exact usecase of the example you listed could be? Is it suppose to be the same boolean rendering different elements when it's true?

<AnimatePresence>
    {bool && <motion.div key="item1" exit="exit"></motion.div>}
    {bool && <motion.div key="item2" exit="exit"></motion.div>}
    {bool && <motion.div key="item3" exit="exit"></motion.div>}
</AnimatePresence>

To add to the above - if you want to do staggering via staggerChildren rather than manually incrementing the delay prop instead of motion.Fragment you could do a motion.div with style={{ display: 'contents' }

<motion.div initial="hidden" animate="visible" exit="hidden" variants={variantsWithStaggerChildren} style={{ display: "contents" }}>
  <motion.div variants={childVariants} />
  <motion.div variants={childVariants} />
  <motion.div variants={childVariants} />
</motion.div>
Was this page helpful?
0 / 5 - 0 ratings