Scroll animation
There are two types of scroll animations:
Scroll-triggered: A normal animation is triggered when an element enters the viewport.
Scroll-linked: Values are linked directly to scroll progress.
Motion is capable of both types of animation.
Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport.
Motion offers the whileInView prop to set an animation target or variant when the element enters the view.
<motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" />
With the inViewOptions , it's possible to set once: true so once an element has entered the viewport, it won't animate back out.
<motion.div initial="hidden" whileInView="visible" :inViewOptions="{ once: true }" />
By default, the element will be considered within the viewport when it enters/leaves the window. This can be changed by providing the ref of another scrollable element.
<script setup> import { ref } from "vue" const scrollRef = ref(null) </script> <template> <div ref="scrollRef" :style="{ overflow: 'scroll' }"> <motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" :inViewOptions="{ root: scrollRef }" /> </div> </template>
For more configuration options, checkout the motion component API reference.
It's also possible to set state when any element (not just a motion component) enters and leaves the viewport with the useInView hook.
Scroll-linked animations are created using motion values and the useScroll hook.
useScroll returns four motion values, two that store scroll offset in pixels (scrollX and scrollY) and two that store scroll progress as a value between 0 and 1.
These motion values can be passed directly to specific styles. For instance, passing scrollYProgress to scaleX works great as a progress bar.
<script> import { useScroll } from "motion-v" const { scrollYProgress } = useScroll(); </script> <template> <motion.div :style="{ scaleX: scrollYProgress }" /> </template>
This value can be smoothed by passing it through useSpring.
<script setup> const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) </script> <template> <motion.div :style="{ scaleX }" /> </template>
With the useTransform hook, it's easy to use the progress motion values to mix between any value, like colors:
<script setup> const backgroundColor = useTransform( scrollYProgress, [0, 0.5, 1], ["#f00", "#0f0", "#00f"] ) </script> <template> <motion.div :style="{ backgroundColor }" /> </template>
Read the full useScroll docs to discover more about creating the above effects.
There are two types of scroll animations:
Scroll-triggered: A normal animation is triggered when an element enters the viewport.
Scroll-linked: Values are linked directly to scroll progress.
Motion is capable of both types of animation.
Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport.
Motion offers the whileInView prop to set an animation target or variant when the element enters the view.
<motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" />
With the inViewOptions , it's possible to set once: true so once an element has entered the viewport, it won't animate back out.
<motion.div initial="hidden" whileInView="visible" :inViewOptions="{ once: true }" />
By default, the element will be considered within the viewport when it enters/leaves the window. This can be changed by providing the ref of another scrollable element.
<script setup> import { ref } from "vue" const scrollRef = ref(null) </script> <template> <div ref="scrollRef" :style="{ overflow: 'scroll' }"> <motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" :inViewOptions="{ root: scrollRef }" /> </div> </template>
For more configuration options, checkout the motion component API reference.
It's also possible to set state when any element (not just a motion component) enters and leaves the viewport with the useInView hook.
Scroll-linked animations are created using motion values and the useScroll hook.
useScroll returns four motion values, two that store scroll offset in pixels (scrollX and scrollY) and two that store scroll progress as a value between 0 and 1.
These motion values can be passed directly to specific styles. For instance, passing scrollYProgress to scaleX works great as a progress bar.
<script> import { useScroll } from "motion-v" const { scrollYProgress } = useScroll(); </script> <template> <motion.div :style="{ scaleX: scrollYProgress }" /> </template>
This value can be smoothed by passing it through useSpring.
<script setup> const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) </script> <template> <motion.div :style="{ scaleX }" /> </template>
With the useTransform hook, it's easy to use the progress motion values to mix between any value, like colors:
<script setup> const backgroundColor = useTransform( scrollYProgress, [0, 0.5, 1], ["#f00", "#0f0", "#00f"] ) </script> <template> <motion.div :style="{ backgroundColor }" /> </template>
Read the full useScroll docs to discover more about creating the above effects.
There are two types of scroll animations:
Scroll-triggered: A normal animation is triggered when an element enters the viewport.
Scroll-linked: Values are linked directly to scroll progress.
Motion is capable of both types of animation.
Scroll-triggered animations are just normal animations that fire when an element enters or leaves the viewport.
Motion offers the whileInView prop to set an animation target or variant when the element enters the view.
<motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" />
With the inViewOptions , it's possible to set once: true so once an element has entered the viewport, it won't animate back out.
<motion.div initial="hidden" whileInView="visible" :inViewOptions="{ once: true }" />
By default, the element will be considered within the viewport when it enters/leaves the window. This can be changed by providing the ref of another scrollable element.
<script setup> import { ref } from "vue" const scrollRef = ref(null) </script> <template> <div ref="scrollRef" :style="{ overflow: 'scroll' }"> <motion.div :initial="{ opacity: 0 }" :whileInView="{ opacity: 1 }" :inViewOptions="{ root: scrollRef }" /> </div> </template>
For more configuration options, checkout the motion component API reference.
It's also possible to set state when any element (not just a motion component) enters and leaves the viewport with the useInView hook.
Scroll-linked animations are created using motion values and the useScroll hook.
useScroll returns four motion values, two that store scroll offset in pixels (scrollX and scrollY) and two that store scroll progress as a value between 0 and 1.
These motion values can be passed directly to specific styles. For instance, passing scrollYProgress to scaleX works great as a progress bar.
<script> import { useScroll } from "motion-v" const { scrollYProgress } = useScroll(); </script> <template> <motion.div :style="{ scaleX: scrollYProgress }" /> </template>
This value can be smoothed by passing it through useSpring.
<script setup> const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30, restDelta: 0.001 }) </script> <template> <motion.div :style="{ scaleX }" /> </template>
With the useTransform hook, it's easy to use the progress motion values to mix between any value, like colors:
<script setup> const backgroundColor = useTransform( scrollYProgress, [0, 0.5, 1], ["#f00", "#0f0", "#00f"] ) </script> <template> <motion.div :style="{ backgroundColor }" /> </template>
Read the full useScroll docs to discover more about creating the above effects.

