Jump to content
Search Community

GSAP ScrollTrigger Pinning With Dynamic Overlay Height in React

Darshan172003

Recommended Posts

Darshan172003
Posted

Issue Overview

I’m building a scroll-based animation in React using GSAP’s ScrollTrigger. The goal: as the user scrolls, a dynamic overlay component should slide upwards to reveal a footer beneath it.


Key Details

  • The overlay component is passed as a prop and can be much taller than the viewport—its height is not known in advance.

  • The section uses h-screen and overflow-hidden. The overlay is absolutely positioned (absolute inset-0) within this section.

  • The animation uses GSAP’s ScrollTrigger to move the overlay up (yPercent: -200), pinning the section as the scroll trigger.

  • The footer remains fixed at the bottom, revealed as the overlay moves away.
     

    Problem Description

  • Any overlay content taller than the viewport is cut off/hidden.

  • Users cannot scroll to view the full overlay content.

  • The scroll reveal animation does not work; only the top portion of the passed overlay is visible.

  • Removing h-screen or overflow-hidden causes layout or animation to break in other ways.

  • Measuring and animating dynamic heights is difficult because absolute positioning and viewport-constrained containers prevent the DOM from sizing correctly.
     

    What I Need Help With

  • How can I allow the animated overlay content to be any height (dynamic, unknown until render)?

  • How do I let the user scroll through all of this content and then smoothly reveal the footer using a slide-up animation?
     

    'use client';
    import React, { useEffect, useRef } from "react";
    import Footer from "../components/Home/Footer/Footer";
    import gsap from "gsap";
    import { ScrollTrigger } from "gsap/ScrollTrigger";
    
    gsap.registerPlugin(ScrollTrigger);
    
    const AnimatedFooterSection = ({ overlayContent = null }) => {
      const finalSectionRef = useRef(null);
      const finalOverlayRef = useRef(null);
    
      useEffect(() => {
        const mq = window.matchMedia('(min-width: 768px)');
        let ctx;
        if (mq.matches && overlayContent) {
          ctx = gsap.context(() => {
            gsap.to(finalOverlayRef.current, {
              yPercent: -200,
              ease: "none",
              scrollTrigger: {
                trigger: finalSectionRef.current,
                start: "top top",
                end: "+=100%",
                scrub: true,
                pin: true,
              },
            });
          });
        }
        return () => {
          if (ctx) ctx.revert();
        };
      }, [overlayContent]);
    
      return (
        <>
          <div className="hidden md:block">
            <section
              ref={finalSectionRef}
              className="section h-screen w-full relative overflow-hidden"
            >
              <div className="content absolute inset-0 flex flex-col items-center justify-center z-10">
                <Footer />
              </div>
              {overlayContent && (
                <div
                  ref={finalOverlayRef}
                  className="overlay absolute inset-0 z-20"
                >
                  {overlayContent}
                </div>
              )}
            </section>
          </div>
          <div className="block md:hidden">
            {overlayContent}
            <Footer />
          </div>
        </>
      );
    };
    
    export default AnimatedFooterSection;

     

GSAP Helper
Posted

Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependencies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen.

that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import GSAP as shown in the Install Helper in our Learning Center : 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

GSAP Helper
Posted

Hi there! I see you're using React -

Proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

Darshan172003
Posted

Hey, thanks for the follow-up and the suggestions!

I've added a minimal StackBlitz demo here for reference:
🔗 vitejs-vite-4i64kaet

The key issue is with dynamically tall overlays being clipped when using absolute positioning inside a pinned section. I kept things simple with colored <div> elements and focused purely on the GSAP ScrollTrigger logic. Let me know if the structure needs further simplification or if there's a more React-friendly approach to handling dynamic height with pinning.

Appreciate any feedback or tweaks—especially if there's a better way to measure & animate unknown height overlays without breaking layout.

 

Posted

Hi,

 

I've been fiddling with your demo and I'm not sure what should be happening here, but it seems like the fact that you're using position absolute is the main problem here, since absolutely positioned elements are taken out of the document's flow and their height is 0px, so they don't give the document or their parent elements any height, as shown in this simple demo:

See the Pen wBKGBoE by GreenSock (@GreenSock) on CodePen.

 

The blue element is inside a parent that has a green background, but since the child element has position: absolute is taken out of the document's flow and doesn't add any height to it's parent.

 

Most likely you'll need to re-think your layout and HTML in order to make this work the way you intend.

 

Hopefully this helps

Happy Tweening!

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...