Adding scroll-based animations can greatly enhance the user experience by creating interactive, visually appealing effects as users scroll through a page. React, combined with libraries like React Spring or Framer Motion, allows you to easily implement animated scroll effects.
In this guide, we will show you how to create animated scroll effects in React, where elements will animate based on the user’s scroll position.
1. Setting Up the Project
If you haven’t already, create a React project and install the necessary animation library. We will use React Spring for this example, but Framer Motion could also be a good alternative.
Install React Spring:
npm install @react-spring/web
or with yarn:
yarn add @react-spring/web
2. Simple Scroll Fade-in Animation
The most common scroll effect is fading in content as the user scrolls to a certain position. We’ll use React Spring‘s useSpring
and animated
components to create this effect.
Example: Fade-in Animation Based on Scroll Position
import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';
const ScrollFadeIn = () => {
const [isVisible, setIsVisible] = useState(false);
const handleScroll = () => {
const scrollPosition = window.scrollY;
// Show the element when the user has scrolled down 200px
if (scrollPosition > 200) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const fadeInStyle = useSpring({
opacity: isVisible ? 1 : 0,
transform: isVisible ? 'translateY(0)' : 'translateY(50px)',
config: { tension: 170, friction: 26 },
});
return (
<animated.div style={fadeInStyle} className="fade-in">
<h2>This will fade in when you scroll!</h2>
</animated.div>
);
};
export default ScrollFadeIn;
Explanation:
useSpring
: The hook defines the animation for the element. The element will fade in and slide up (translateY(0)
) when it becomes visible.useEffect
: This listens for the scroll event. When the scroll position exceeds 200px, it sets the element to be visible and animates it.animated.div
: This component is animated with the styles returned byuseSpring
.
3. Scroll Animations with useSprings
for Multiple Elements
If you want to animate a list of items or multiple elements on scroll, you can use useSprings
, which allows you to animate multiple items simultaneously.
Example: Fade-In Multiple Items on Scroll
import React, { useState, useEffect } from 'react';
import { useSprings, animated } from '@react-spring/web';
const ScrollList = () => {
const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
const [isVisible, setIsVisible] = useState(Array(items.length).fill(false));
const handleScroll = () => {
const scrollPosition = window.scrollY;
const newVisibility = items.map((_, index) => scrollPosition > (index + 1) * 150);
setIsVisible(newVisibility);
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const springs = useSprings(
items.length,
items.map((_, index) => ({
opacity: isVisible[index] ? 1 : 0,
transform: isVisible[index] ? 'translateY(0)' : 'translateY(50px)',
config: { tension: 170, friction: 26 },
}))
);
return (
<div>
{springs.map((style, index) => (
<animated.div key={index} style={style} className="scroll-item">
{items[index]}
</animated.div>
))}
</div>
);
};
export default ScrollList;
Explanation:
useSprings
: This hook creates animations for multiple elements. It takes an array of animations, each of which corresponds to one element.isVisible
: This state tracks whether each item should be visible based on the scroll position. Each item becomes visible after scrolling past its threshold.
4. Scroll-based Parallax Effect
A parallax effect gives the illusion of different layers moving at different speeds. This can be achieved by modifying an element’s position based on scroll speed.
Example: Parallax Scroll Effect
import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';
const ParallaxEffect = () => {
const [scrollPosition, setScrollPosition] = useState(0);
const handleScroll = () => {
setScrollPosition(window.scrollY);
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const parallaxStyle = useSpring({
transform: `translateY(${scrollPosition * 0.3}px)`, // Moves slower than the scroll
});
return (
<animated.div style={parallaxStyle} className="parallax">
<h2>This element moves slower than the scroll</h2>
</animated.div>
);
};
export default ParallaxEffect;
Explanation:
scrollPosition
: The scroll position is tracked, and we adjust the translation of the element based on the scroll position.- Parallax Effect: The element moves slower than the scroll itself (using a multiplier of
0.3
), creating a parallax effect.
5. Scroll-triggered Slide-in Animation
Another popular effect is having elements slide in from the sides or bottom as the user scrolls down the page.
Example: Slide-in from the Bottom on Scroll
import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';
const ScrollSlideIn = () => {
const [isVisible, setIsVisible] = useState(false);
const handleScroll = () => {
const scrollPosition = window.scrollY;
// Show the element when the user has scrolled down 300px
if (scrollPosition > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const slideInStyle = useSpring({
transform: isVisible ? 'translateY(0)' : 'translateY(100px)',
opacity: isVisible ? 1 : 0,
config: { tension: 170, friction: 26 },
});
return (
<animated.div style={slideInStyle} className="slide-in">
<h2>This slides in when you scroll!</h2>
</animated.div>
);
};
export default ScrollSlideIn;
Explanation:
useSpring
: The element slides in from below when the user scrolls past 300px, using thetransform
property.opacity
: The element also fades in as it slides into view.