Jump to content
Search Community

Issue with ScrollSmoother and ScrollTrigger pin behavior in Next.js

_kino

Recommended Posts

Posted

Hi @GreenSock team,
First of all, thank you for the amazing work you’re doing!

I’ve been learning GSAP for a few months now, and recently I ran into a problem that I can’t seem to solve. I’d really appreciate your help.

I’m working on a Next.js app where I’m using both ScrollSmoother and ScrollTrigger.
While searching through the docs, forums, and GitHub, I found this demo: https://stackblitz.com/edit/stackblitz-starters-cxedmc?file=app%2Fpage.tsx

In that demo, the ScrollSmoother is created inside a layout that’s been converted to a client component using "use client".
In my case, I’d like to avoid converting my root layout to a client component, since it contains all the metadata.
Are there any recommended alternatives or best practices for handling this in Next.js?

Another issue I’m facing is with pinning behavior,  it doesn’t work as expected. Interestingly, the same issue appears in the demo I found, and my setup for the pin in my app is quite similar to that demo.

Has anyone run into something similar or found a workaround for this setup in Next.js?
Thanks a lot in advance for your time and help!

Posted

Hi @_kino and welcome to the GSAP Forums!

 

Actually a client component is still rendered in the server and then hydrated on the client, but if you still want to have that as a server component you can create an extra component that creates and updates the ScrollSmoother instance and add that in the layout file:

ScrollSmoother component

"use client";
// imports here

export default function SmootherComponent() {
  const pathname = usePathname();

  useGSAP(
    () => {
      ScrollSmoother.create({
        smooth: 2,
        effects: true,
      });
    },
    {
      dependencies: [pathname],
      revertOnUpdate: true,
    }
  );
  
  return (
    <Header />
    <div id="smooth-wrapper">
      <div id="smooth-content">{children}</div>
    </div>
  );
};

Then use it like this in the layout file:

// other imports
import SmootherComponent from "/route-to-components/SmootherComponent";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body className={inter.className}>
        <SmootherComponent>
          {children}
        </SmootherComponent>
      </body>
    </html>
  );
}

That should work the way you expect.

 

Hopefully this helps. If not please create a minimal demo that clearly illustrates the issue since I can see that the pinning works as expected in our demo.

Happy Tweening!

Posted

Hi @Rodrigo,
Thanks a lot for your quick reply. The <SmootherComponent> solution works really well for my setup.

However, I’m a bit confused that the pin seems to work fine on your end. I just tested the demo again on two different computers and three browsers, and I still see the same issue. (Sometimes it works the first time, but once the page is refreshed, the pin stops working.)

Here’s a demo using the <SmootherComponent> as recommended  it only includes the three boxes, and the “C” box is pinned: https://stackblitz.com/edit/stackblitz-starters-5dppkqdk?file=app%2Fpage.tsx

In case this demo doesn’t reproduce the pin behavior I’m seeing on my side, I’ve also recorded a Loom video here: https://www.loom.com/share/939e465e36e048d9991cdbcd5ff1c66a?sid=545f6fad-40e9-41b8-bdff-37cdc6802ea8

Thanks again for your help and for taking the time to look into this!

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...