reactjsframer-motionframerjs

React Framer Motion - List with Staggered Children Animation Not Working on Removal


I have this repro here of a motion.ol and motion.li that appear and disappear. However, the animation on exit does not work on the motion.li.

The parent code:

const variantsBoxContainer: Variants = {
  hidden: {
    opacity: 0,
    transition: {
      staggerChildren: 0.1,
      delayChildren: 0.3
    }
  },
  show: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,
      delayChildren: 0.3
    }
  }
};

let id = 3;
export const ParentBox = (props: ParentBoxProps) => {
  const [items, setItems] = useState<Item[]>([
    { id: 1, text: "Test #1" },
    { id: 2, text: "Test #2" }
  ]);
  return (
    <motion.div
      className="parentbox"
      // style={{ transform: `translateX(${props.showBox ? 0 : 100}px)` }}
    >
      <button
        onClick={() => {
          id++;
          setItems([...items, { id: id, text: `Click to delete id ${id}` }]);
        }}
      >
        Add
      </button>

      <motion.ol
        variants={variantsBoxContainer}
        initial="hidden"
        animate="show"
        exit="hidden"
      >
        <AnimatePresence>
          {items
            .sort((a, b) => a.id - b.id)
            .map((d) => (
              <Box
                key={d.id}
                data={d}
                onRemove={(item) => {
                  const newList = items.filter((i) => i.id !== item.id);
                  console.log(newList);
                  setItems(newList);
                }}
              />
            ))}
        </AnimatePresence>
      </motion.ol>
    </motion.div>
  );
};

The child (Box) code:

const variantBox: Variants = {
  hidden: { opacity: 0, top: -100 },
  show: { opacity: 1, top: 0 }
};
export const Box = (props: BoxProps) => {
  return (
    <motion.li
      className="box"
      variants={variantBox}
      onClick={() => {
        props.onRemove(props.data);
      }}
    >
      {props.data.text}
    </motion.li>
  );
};

I've tried several configurations like having a layout or layoutid but the animation was getting worse. I removed the AnimatePresence but that did not help.

Anyone has an idea?

Codesandbox


Solution

  • You need to specify which variants to use for the initial, animate, and exit props of your Box component.

    <motion.li
      className="box"
      variants={variantBox}
      initial="hidden"
      animate="show"
      exit="hidden"
      onClick={() => {
        props.onRemove(props.data);
      }}
    >