Reputation: 3703
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.
Upvotes: 21
Views: 44069
Reputation: 304
you can also use this one
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true, amount: 0.5 }}
>
hello
</motion.div>
Upvotes: 1
Reputation: 5902
framer-motion
has built-in support for this use case since version 5.3.
Here's a CodeSandbox demonstrating the pattern: https://codesandbox.io/s/framer-motion-animate-in-view-5-3-94j13
Relevant code:
function FadeInWhenVisible({ children }) {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
transition={{ duration: 0.3 }}
variants={{
visible: { opacity: 1, scale: 1 },
hidden: { opacity: 0, scale: 0 }
}}
>
{children}
</motion.div>
);
}
Usage:
<FadeInWhenVisible>
<Box />
</FadeInWhenVisible>
Previous versions:
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>
);
}
Upvotes: 75