Jump to content
Search Community

GSAP Page Transitions in Next.js

John Polacek test
Moderator Tag

Recommended Posts

Hey everyone!

 

I've been working on a fun demo project called TweenPages to show how I do complex page transitions with GSAP in Next.js. I haven't shared it yet with anyone publicly until now. Would love to get some early feedback. Especially on the docs where I go into detail on the code side of things. Am I doing it right? Am I doing it wrong? Are there things I can improve? 

 

Fun! - https://tweenpages.vercel.app/

Docs - https://tweenpages.vercel.app/docs

Code - https://github.com/johnpolacek/TweenPages

 

Hope the project helps anyone who want to do GSAP animations like these on Next.js.

 

  • Like 15
Link to comment
Share on other sites

  • 2 weeks later...
  • 1 month later...
  • 6 months later...
  • 6 months later...

There shouldn’t be any difference in using gsap with  Next 13 app directory as far as I’m aware. The only thing is Next 13’s app directory uses React server components by default until you mark a component as client.  You can’t use gsap in server components since server components do not allow useEffect() which gsap with React relies on. So use it in the components marked as client.  (Also worth noting Next 13’s app directory is still in beta)

  • Like 2
Link to comment
Share on other sites

Thanks, @omarel ...I know it's beta, but since it's a side project and something that probably won't come online, I am also using it as an opportunity to learn next + GSAP. To be honest also trying to decide if GSAP or Framer Motion is a better fit for my needs and way of working.

RE: GSAP working in next.js 13, I think you're right... no issues as long as you mark the right files with "use client". But as I am learning, I wanted to pick apart exactly this demo / resource ...which is wonderful, and to see it working and adapted to the new app model.

 

I am also trying to be convinced that page transitions, more specifically exit page transitions, are working *at all* in next.js at present, again...using the app approach. But I am not sure if the failure is with next.js or Framer Motion.

 

I'm using "failure" gently here, I know, I know... it's beta! :)

 

 

Link to comment
Share on other sites

Yep that was the first thing I did... and it didn't go well! But I went straight for a conversion to the app folder, probably ambitious :)

 

I'll try again tomorrow and see if I can get it stable in /pages and on 13, and then take it from there. 🙏

Link to comment
Share on other sites

Hi,

 

In the mean time while either John or someone else can update the package to work with NextJS 13, here is a simple example that uses GSAP and React Transition Group to create the animated transitions between pages:

https://stackblitz.com/edit/nextjs-13cw4u

 

Right now it seems that Stackblitz has a few issues with their webcontainer (what they use to run Node and SSR on the browser). Here is the same example but using React and React Router:

https://stackblitz.com/edit/react-6rzfpp

 

Hopefully this helps in the meantime. Let us know if you have more questions.

 

Happy Tweening!

  • Like 2
Link to comment
Share on other sites

Awesome. Thanks @Rodrigo. I have looked for a way to export the nextJS 13 example to codesandbox.io, hoping maybe it would run there. 🧐 Not sure if that is a function in stackblitz and I just can't find it, or if it's not possible. Otherwise I can rebuild it from the package.json and give it a spin. Or locally.

 

I'll let you know how I get on.

Link to comment
Share on other sites

  • 4 months later...

Really like the idea because I don't need to install any other dependencies.

Also the logic of the intro/outro animation can be clear thanks to GSAP.

 

I tried to do some page transitions with Next.js and three.js using this technique.

What I want to achieve is to combine both html and threejs element in intro/outro animations.

Demo

 

After I finished the demo, I wrap the context into a tiny package for my own reuse.

@chundev/gtranz

 

I remove the setTimeline, background, setBackground in the context because I didn't use them at all and that also make sure context does not trigger re-render because of state change. The context itself is very simple you can just grab the code from src folder if you need it.

 

 

I want to share the biggest problem I encountered.

As I wrote in the Github readme, if I tweened something that is already be set in the outro.

(I need instant scroll animation of the images which are also the outro elements)

 

That will break the transition later because as I researched, one element can only have one tween at a time.

(I could barely find information about this topic and struggled for a while)

 

So I set the default to overwrite:true (default is false, in the original post, it only do the simplest css intro/outro so no problems) and arrange the order of animation setup by myself.

 

 

What I did was:

1. use a state to determine the setup order of intro/outro. (if you overwrite some tweens that are used in the outro.)

2. use custom event to re-setup outro whenever you want (mostly after the animation that tweened the same element, with onComplete callback)

 

I don't really know if it's good practice or not.

But I did solve my problem and make nice transition by doing so.

 

Just want to share my experience.

I really love this community and learn so much things here. Thank you!

  • Thanks 1
Link to comment
Share on other sites

Hi @latteouka. Thanks for sharing. I don't have time to dig through all that code but I wanted to make sure I pointed out that this is not true: 

7 hours ago, latteouka said:

one element can only have one tween at a time.

There are no such limits. But you shouldn't create multiple simultaneous tweens that are all trying to control the same property of the same element because obviously the same value can't go in a bunch of different directions at the same time. 

 

You might want to consider overwrite: "auto" which only overwrites individual overlapping properties rather than entire tweens (which is what overwrite: true does). 

 

If you've got any GSAP-specific questions that you'd like answered, feel free to post them here. 

  • Like 1
Link to comment
Share on other sites

Hi @GreenSock,

 

Thanks for pointing out my misunderstanding.

It really helps me understand how the timeline and overwrite works!

 

After building a tiny playground, I found my problem was not about overwriting but states.

See the Pen gOBmYxz?editors=1010 by latteouka (@latteouka) on CodePen

 

I was trying to tween some "current" elements which need to be set again because "current index" have changed.

That is why I was trying to find some solutions about overwriting conflicts.
I also had some problems with tweening something before the last delay animation is not yet played.

 

I am happy to stay with the default overwrite: false and more confident about tuning my page transition now.

 

Thank you again for the help.

  • Like 1
Link to comment
Share on other sites

  • 1 month later...
On 6/8/2023 at 10:01 AM, Silvia Malavasi said:

Hi. I ended up with creating a custom router event handler to control transition between pages.

Here's the repo:
https://github.com/SilviaMalavasi/next-13-page-transition-gsap

And here's deployed on Vercel
https://next-13-page-transition-gsap.vercel.app/

 

 

 

I am curious if there is anything lost, or features of Next.js 13.4 that will be missed out on by not using <Link> to navigate pages? For ex. prefetching or ... yeah ...not sure :) 

Link to comment
Share on other sites

  • 2 months later...

I managed to create a page transition using the Next 13 App router. However, I'm quite certain that this isn't the optimal approach. I encountered an issue where, due to the heftiness of my pages, the animation would unexpectedly occur before the page had completely loaded. Since the useRouter router in Next 13 does not return a Promise, I couldn't wait for the page to load before triggering my animation. Because of this, I resorted to using a good old setTimeout. I also attempted to use the useTransition hook from React, but I encountered some strange behavior.

 

Here's a minimal code example of what I did. I'm open to any suggestions for improvement. I'm sharing this because it might be helpful to others.

 

const RootLayout = async ({
  children,
}: {
  children: React.ReactNode;
}) => {
  return (
    <html>
      <body>
          <TransitionProvider>
                <Navbar />
                <TransitionHandler>
                  {children}
                </TransitionHandler>
          </TransitionProvider>
      </body>
    </html>
  );
};

 

export const TransitionContext = createContext<{
  url: string;
  setUrl: Dispatch<SetStateAction<string>>;
}>({
  url: "",
  setUrl: () => {},
});

const TransitionProvider = ({ children }: { children: ReactNode }) => {
  const pathname = usePathname();
  const [url, setUrl] = useState<string>(pathname);

  return (
    <TransitionContext.Provider value={{ url, setUrl }}>
      {children}
    </TransitionContext.Provider>
  );
};

export default TransitionProvider;
export default function TransitionHandler({
  children,
}: {
  children: ReactNode;
}) {
  const elementReference = useRef(null);
  const firstLoadReference = useRef(true);
  
  const router = useRouter();
  
  const { url, setUrl } = useContext(TransitionContext);

  useEffect(() => {
    if (!firstLoadReference.current) {
      const element = elementReference.current;

      const onPageExit = (element: null) => {
        router.prefetch(url);
        // your page exit animation
      };

      const onPageEnter = (element: null, url: string) => {
        router.push(url);

        // TODO: find a better solution
        setTimeout(() => {
          // your page enter animation
        }, 500);
      };

      onPageExit(element);
    }
    firstLoadReference.current = false;
  }, [router, url, firstLoadReference]);

  return <div ref={elementReference}>{children}</div>;
}
const Navbar = () => {
  const {url, setUrl} = useContext(TransitionContext);
  
  return (
    <button onClick={() => setUrl("/my-url")}
		click
    </button>
)}

 

Link to comment
Share on other sites

Hi @nina-alin and welcome to the GreenSock forums!

 

In our Next Page Transition starter template, we use a React context wrapper to check when the transition animation is completed in order to trigger the animations in the page once the animation is completed. I'd suggest you  to follow the same pattern in order to create your GSAP instances:

https://stackblitz.com/edit/nextjs-13cw4u?file=context%2FTransitionContext.js,pages%2Flayers.js

 

Hopefully this helps. If you keep having issues, please provide a minimal demo that clearly illustrates the problem you're having.

Happy Tweening!

Link to comment
Share on other sites

Hi, I've tried to refactor "GSAP Page Transitions Next13" example to work with app router.

 

Your example with pages router:
https://stackblitz.com/edit/nextjs-13cw4u

 

After changes when you click a link it first loads a new page and only then starts transitions.

 

Just to be clear what I mean:

how it should be: click the link => transitions out an old page => transitions in a new page,

how it is: click the link => immediately loads a new page => transitions out a new page => transitions in a new page.

 

Repo after changes:
https://github.com/szn-a/nextjs-nvdumc


Above code throws an error on stackblitz.com when trying to navigate it runs ok locally and on my vps.

 

Any suggestions?

 

Regards

Link to comment
Share on other sites

Hi @szn and welcome to the GreenSock forums!

 

At a quick glance I can see that you're not using the Transition Context's complete state property in your effect hooks in order to create the ScrollTrigger instances on your pages, but that doesn't seem to be the main issue here.

 

I'm not very familiar with Next's app router so I'll create an example and keep you posted about it.

 

The reason Stackblitz is having issues is because their platform for running a Node environment on the browser (webcontainer) is not fully compatible with the latest versions of Next.

 

Happy Tweening!

Link to comment
Share on other sites

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