How to Use the GSAP ScrollTrigger Plugin in React

Create engaging, scroll-based animations that enhance user experience and keep visitors immersed in your content

Introduction

Scroll-triggered animations have become a defining characteristic of modern, engaging web experiences. When users scroll down a page and elements smoothly reveal themselves, follow their viewport position, or trigger interactive sequences, the experience feels polished and intentional. GSAP's ScrollTrigger plugin, combined with React's component architecture, gives developers a powerful toolkit for creating these experiences.

However, implementing scroll-based animations requires careful attention to performance, cleanup, and user experience considerations. This guide walks through the fundamentals of using ScrollTrigger in React, covering setup, core concepts, practical patterns, and performance optimization techniques that ensure your animations enhance rather than hinder the user experience.

For teams building custom web applications, mastering scroll animations can significantly improve engagement metrics and time-on-site.

Understanding ScrollTrigger: Core Concepts

What ScrollTrigger Does

ScrollTrigger works by establishing specific scroll positions at which animations should begin, end, or update. Unlike older approaches that constantly check element positions (which can severely impact performance), ScrollTrigger calculates trigger points upfront during initialization and only monitors the scroll position itself. This approach maintains smooth scrolling performance while enabling sophisticated animation control, as documented in the GSAP ScrollTrigger Documentation.

Key Configuration Options

Trigger: The element that activates the ScrollTrigger. Can be a selector string or DOM element reference.

Start: Defines when the trigger activates relative to the viewport. Format: "triggerPosition viewportPosition" (e.g., "top 80%" means when the top of the trigger hits 80% down the viewport).

End: Defines when the trigger's active state ends. Can be a pixel value, percentage, or relative scroll distance (e.g., "+=500" means 500 pixels of scrolling beyond the start).

Scrub: Links the animation directly to scroll position. Setting scrub: true makes the animation follow scroll exactly, while scrub: 1 adds a 1-second smoothing delay.

Pin: Locks an element in place during the scroll animation, preventing it from scrolling out of view.

Snap: Forces the scroll to land on specific animation points, creating a polished feel.

The Scroll Position Syntax

The start and end properties use a two-value syntax that combines trigger position with viewport position. The first value references the trigger element (top, center, bottom), while the second references the viewport (top, center, bottom). You can also use pixel offsets or percentages.

When building responsive web applications, understanding these configuration options allows you to create animations that work seamlessly across all screen sizes and devices.

Setting Up ScrollTrigger in a React Project

Installation and Import

npm install gsap

Then import and register the plugin in your React component:

import { useEffect } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

For React-specific projects, the useGSAP hook (introduced in newer GSAP versions) provides cleaner integration with automatic cleanup:

import { useGSAP } from 'gsap/react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

Creating Your First ScrollTrigger Animation

import { useRef } from 'react';
import { useGSAP } from 'gsap/react';
import gsap from 'gsap';

function AnimatedSection() {
 const sectionRef = useRef(null);

 useGSAP(() => {
 gsap.from(sectionRef.current, {
 scrollTrigger: {
 trigger: sectionRef.current,
 start: "top 80%",
 end: "top 20%",
 scrub: 1,
 },
 opacity: 0,
 y: 100,
 duration: 1
 });
 }, { scope: sectionRef });

 return (
 <section ref={sectionRef}>
 <h2>This section animates on scroll</h2>
 <p>Content that fades in and slides up as users scroll.</p>
 </section>
 );
}

This pattern demonstrates the core workflow for integrating scroll animations into your React development projects. The useGSAP hook ensures proper lifecycle management and automatic cleanup when components unmount.

Building Practical Scroll Animations

Reveal Animations on Page Scroll

Reveal animations are among the most common scroll-triggered effects. As users scroll down, elements smoothly fade in, slide up, or scale into view. This pattern works well for feature sections, testimonials, pricing cards, and any content that benefits from drawing attention as it enters the viewport.

import { useRef } from 'react';
import { useGSAP } from 'gsap/react';
import gsap from 'gsap';

function FeatureCard({ title, description, index }) {
 const cardRef = useRef(null);

 useGSAP(() => {
 gsap.from(cardRef.current, {
 scrollTrigger: {
 trigger: cardRef.current,
 start: "top 90%",
 toggleActions: "play none none reverse"
 },
 opacity: 0,
 y: 50,
 duration: 0.8,
 delay: index * 0.1
 });
 }, { scope: cardRef });

 return (
 <div ref={cardRef} className="feature-card">
 <h3>{title}</h3>
 <p>{description}</p>
 </div>
 );
}

The toggleActions property controls when the animation plays: "play none none reverse" plays the animation when the trigger enters the viewport, then reverses it when the trigger leaves. Other options include pause, resume, and complete actions.

Pinning Elements During Scroll

Pinning holds an element in place while the user continues scrolling, creating opportunities for side-by-side content, sticky navigation, or animation sequences that unfold over a scroll distance. This technique is particularly effective for landing page design, allowing you to present complex information without overwhelming users.

Parallax Effects

Parallax creates depth by moving background and foreground elements at different speeds during scroll. This technique adds visual interest and can guide user attention toward key content, a staple of modern front-end development practices.

Horizontal Scroll Sections

Horizontal scroll sections offer an alternative navigation experience that can showcase galleries, timelines, or process steps in an engaging format. This approach works particularly well for portfolio presentations and case study showcases.

React-Specific Best Practices

Using useRef for Element Targeting

React's declarative nature differs from GSAP's imperative approach. useRef bridges this gap by providing direct access to DOM elements without triggering re-renders. Always use refs instead of selector strings when possible, as refs maintain stability even when React re-renders components. This is especially important in React applications where component updates are frequent.

// Recommended: Using refs
function Component() {
 const elementRef = useRef(null);

 useGSAP(() => {
 gsap.to(elementRef.current, {
 scrollTrigger: { trigger: elementRef.current, start: "top 80%" },
 rotation: 360
 });
 }, { scope: elementRef });

 return <div ref={elementRef}>Animated Element</div>;
}

Proper Cleanup and Memory Management

Memory leaks from unmanaged ScrollTrigger instances can cause significant performance issues, especially in single-page applications with frequent component mounting and unmounting. Always clean up ScrollTriggers when components unmount using gsap.context(), as demonstrated in GSAP React animation guides:

import { useRef } from 'react';
import { useGSAP } from 'gsap/react';
import gsap from 'gsap';

function AnimatedComponent() {
 const containerRef = useRef(null);

 useGSAP(() => {
 const ctx = gsap.context(() => {
 gsap.from('.animate-item', {
 scrollTrigger: {
 trigger: '.animate-item',
 start: "top 85%"
 },
 opacity: 0,
 y: 30
 });
 }, containerRef);

 return () => ctx.revert();
 }, { scope: containerRef });

 return (
 <div ref={containerRef}>
 <div className="animate-item">Content</div>
 </div>
 );
}

The gsap.context() wrapper collects all animations created within its scope, making cleanup straightforward with a single ctx.revert() call. This approach is particularly valuable when animating multiple elements or using loops.

useLayoutEffect vs useEffect

useLayoutEffect fires synchronously after all DOM mutations, making it ideal for animations that need to measure element positions before rendering. useEffect fires after the paint, which can cause visible jumps for layout-sensitive animations. For most scroll-triggered animations, useGSAP handles this automatically.

Performance Optimization

Understanding ScrollTrigger's Performance Model

ScrollTrigger does not constantly watch every element and check its positioning in the viewport on each scroll tick. Instead, it calculates start and end positions upfront during initialization, then debounces scroll events and only updates on requestAnimationFrame, perfectly synchronized with GSAP and screen refreshes, as described in the GSAP ScrollTrigger Documentation. This approach maintains 60fps scrolling even with multiple active triggers.

Optimizing for Low-End Devices

For users on mobile devices or older computers, scroll animations can strain resources. Several strategies help maintain smooth performance:

Limit active triggers: Only create ScrollTrigger instances for elements currently in or near the viewport. Lazy-loading content that creates triggers when approaching the viewport reduces unnecessary calculations.

Use CSS transforms: Animate transforms (x, y, scale, rotation) instead of properties like width, height, or margin, which trigger layout recalculations, as noted in production ScrollTrigger implementations.

Set will-change: Add CSS will-change: transform to elements that will be animated, helping the browser optimize compositing layers.

.animated-element {
 will-change: transform;
}

Consider pure CSS alternatives: For simple reveal effects, CSS transitions with Intersection Observer may use fewer resources than ScrollTrigger. Reserve GSAP for cases requiring its advanced features, particularly when building performance-optimized web applications.

When implementing scroll animations, always test on real devices to ensure your responsive design solutions perform well across the full range of user hardware.

Advanced Patterns and Use Cases

Dynamic Content and React State

When ScrollTrigger elements are added, removed, or changed, you need to refresh the trigger calculations by calling ScrollTrigger.refresh() when content changes. This is common in single-page applications with dynamic content loading.

Combining Multiple ScrollTriggers

Complex interfaces often require multiple ScrollTriggers working together. The timeline approach coordinates sequential animations:

const tl = gsap.timeline({
 scrollTrigger: {
 trigger: containerRef.current,
 start: "top 70%",
 end: "bottom 70%",
 scrub: 1
 }
});

tl.from('.heading', { opacity: 0, y: 30, duration: 1 })
 .from('.subheading', { opacity: 0, y: 20, duration: 0.5 }, "-=0.5")
 .from('.cta', { opacity: 0, scale: 0.8, duration: 0.5 }, "-=0.3");

ScrollTrigger Callbacks and State Updates

ScrollTrigger provides callbacks for executing code at specific points: onEnter, onLeave, onEnterBack, onLeaveBack, onToggle, onUpdate, onScrubComplete, and onRefresh. These callbacks enable integration with React state and side effects.

When building interactive web experiences, these advanced patterns allow you to create sophisticated animations that respond to user behavior and content changes.

Common Pitfalls and Solutions

ScrollTrigger Not Firing

If ScrollTrigger doesn't activate as expected:

  • Ensure your useGSAP hook runs after the component mounts
  • Verify the trigger element exists and is correctly targeted
  • Try loosening start/end positions (e.g., "top 90%" instead of "top 70%")
  • Check for z-index or visibility issues

Use markers: true during development to visualize trigger positions.

Memory Leaks from Uncleaned Animations

Always use gsap.context() for cleanup, especially in components that may mount and unmount frequently. The ctx.revert() call ensures all ScrollTrigger instances are properly cleaned up when components unmount, preventing memory leaks that can degrade performance in long-running web applications.

Conflicts with Native Scroll Behavior

  • Avoid scroll-jacking that prevents or overrides native scrolling
  • Ensure animations don't make content inaccessible
  • Test on actual mobile devices, not just emulators
  • Respect accessibility preferences for reduced motion

When implementing scroll animations for accessible web design, always consider users who may be sensitive to motion and provide graceful fallbacks.

Conclusion

GSAP ScrollTrigger combined with React creates powerful possibilities for creating engaging, scroll-based user experiences. The key to success lies in understanding the fundamentals of scroll positioning, using proper React patterns with refs and cleanup, and optimizing for performance across all devices.

Start with simple reveal animations, then progressively add more complex features like pinning, parallax, and coordinated timelines as you become more comfortable with the API. Always test on real devices, gather user feedback, and iterate on your implementations to create experiences that genuinely enhance rather than distract from your content.

When implemented thoughtfully, scroll-triggered animations can guide user attention, create memorable experiences, and keep visitors engaged with your content longer. For teams looking to elevate their web presence, mastering these techniques represents a significant step toward creating compelling digital experiences.

Our UI/UX design services can help you integrate scroll animations and other modern techniques into your web projects for maximum impact.

Key Takeaways

Use refs for targeting

Always use useRef instead of selector strings for stable element access in React

Clean up properly

Use gsap.context() with ctx.revert() to prevent memory leaks

Optimize performance

Limit triggers, use CSS transforms, and test on low-end devices

Respect user experience

Avoid scroll-jacking and respect reduced motion preferences

Frequently Asked Questions

Ready to Create Engaging Scroll Animations?

Our UI/UX team specializes in creating performant, accessible animations that enhance user experience.