Framer motion animate when element is in-view (When you scroll to element)

Ali Elkhateeb picture Ali Elkhateeb · Nov 20, 2019 · Viewed 9.6k times · Source

Is there any built-in way to make the animation start when the element is in-view (for example, when we scroll to the element)?

Framer Motion has mount animations section which says:

When a component mounts, it'll automatically animate to the values in animate if they're different from those defined in style or initial

So I couldn't really find a straight forward way to make the animation start when it comes into view.

However, I reached the only option I see for now is using Animation Controls which means I'll have to implement a listener on the scroll manually and trigger the control.start(), any easier ways are much appreciated.

Answer

amann picture amann · Feb 20, 2020

There is currently no built in way to achieve this. However as you mentioned, you can currently use the imperative animation controls to achieve this effect. Intersection observers are useful to detect if an element is currently visible.

Here's a CodeSandbox demonstrating the pattern: https://codesandbox.io/s/framer-motion-animate-in-view-gqcc8.

Relevant code:

function FadeInWhenVisible({ children }) {
  const controls = useAnimation();
  const [ref, inView] = useInView();

  useEffect(() => {
    if (inView) {
      controls.start("visible");
    }
  }, [controls, inView]);

  return (
    <motion.div
      ref={ref}
      animate={controls}
      initial="hidden"
      transition={{ duration: 0.3 }}
      variants={{
        visible: { opacity: 1, scale: 1 },
        hidden: { opacity: 0, scale: 0 }
      }}
    >
      {children}
    </motion.div>
  );
}

Usage:

<FadeInWhenVisible>
  <Box />
</FadeInWhenVisible>