How to Make Page Transitions using Next.js and GSAP

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
a lot of you guys have been asking me how can we make a page transition in nexj with gap and although there are many many videos on the subject already I've taken a quick look at them and many of them have a lot of mistakes the number one mistake that I see out there is that they just don't have an exit animation all right it's just an entry animation and to me that's just not a proper solution it's not a proper page transition if there are no exit animation another thing that I saw is they use the app router and since it's not officially supported they do it in a hacky way by doing it with a non- click on a button and so they're not actually using the next link and to me that's a bit problematic because it's not good for accessibility not good for SEO and many other reasons so today I want to take a look at my solution what I would do if I had to make a page transition in next J with gsab for like a real client for a real project so let's get right into it all right so the starting projects looks like this have three pages and a header just a really simple project here and the goal is to have something like this if I refresh here going to see I have an entry animation initially and then if I change page I'm going to have an exit animation and a different entry animation depending on which page right so I want to have full control over the animation depending on which page I am so that's the final result and even if I scroll I'm going to have a nice final result like this so it's actually useful for a real world project and also it's important to mention that this is using the page router all right like I said before it's not officially supported on the app router so just to be clear this is using the page router and also I want to give credits where it's to Due um I highly inspired myself from this guide created by John pich he made this years ago something like a guide for a next page transition using gsap and it's actually a bit outdated so it's not working anymore but still the concepts here were really interesting and I highly inspired myself to create my own solution so yeah I just want to give credits where it's due if you're interested you can check it out I'll put it in the description unfortunately it's not working anymore cuz it's a bit of a old guy but still the concepts are really interesting and I basically took it I added my own sauce and I also simplified it just to make it a bit more clear for you guys so let's start with this the hardest thing normally when doing page transition is the exit animation all right the entry animation really easy you can just have a use effect or a use Gap hook and then inside of it you have a gab to and with that you have an entry animation it's not really complicated the hard part really is the exit animation so I want to spend a lot of time on that and what I want to do here is basically find a way to delay the transition of my page right now when I click link it directly goes to the other page and I have no time to create an exit animation so I need to find a way to delay that transition and now what I want to do to control the transition of the page a bit similar to what we do in frame motion all right in frame motion we would add like an animate presence and we would wrap our components with that but now instead we're going to create our own custom thing so here I'm going to add a transition wrapper so for that I'll create in my components folder a a transition component here inside of it I'm going to have an index and now my transition wrapper is going to take the children as a props and I can simply here return the children and now inside of my app.js I can import the transition here and I'm going to take it here and wrap all of my component with it something like that and with that we should have the same thing that we had before right but now inside of my transition component I have access to the children which are all of the different pages and so now how can we control them well the first thing that I'm going to do here is create a state all right I'm going to have a const and I'm going to have here the display children and I'm going to have the set display children and that's going to be equal to the use State hook and initially I'm going to have it be the current page so just a reminder here the component is the children of the transition wrapper and so inside of it here the children is the current page initially and so then I can take my display children and put it here and if I save that I should have the same thing on first load but now if I decide to change my page you're going to see that the routing is changing but I'm still seeing the Project's page and that's because initially the display children is going to be the first page at the first load right and so for example if I go in the homepage and here I'm going to refresh then it's going to be the home and then if I do about projects not doing anything and if I refresh now I'm in the projects right so now all I have to do is set the display children if I want to change change the display of the page so for example what I could do is have a use effect and here that use effect could have the children as a dependency and so every time the children changes here I'm going to do a set display children to the new children and so with that I should have my normal page transition I'm going to try this home about projects really normal the normal behavior of a routing but now I'm actually controlling what's happening so if I want to delay it I can do a set timeout so this is just an example now I'm going to do like one second and then inside of it I can put my set display children and now the transition of the page should be delayed by 1 second let's try it going to go to the homepage and you see there's a second delay but it's only the display that is delayed because the routing is actually instantly changing but not the display so that's pretty good because I'm not hijacking the routing all I'm hijacking is the display of the page but now let's say I actually want to create an exit animation I'm going to create a fade in Fade Out animation so the first thing I'm going to do here is add a reference to The Container here and with that I can actually Target it in change the opacity so I'm going to have here a container it's going to be equal to the use ref and then instead of doing this set time out here instead I'm going to use Gap so here I'm going to import Gap from gsop and I'm also going to import the used gsop which is what you kind of want to use uh when using react with gsop and then you can do gap. register plugin just to to make sure that everything is working and then instead of doing a use effect I'm going to do a use Gap here instead and that's basically the same thing as a use effect but it's also going to do the cleanup for us and other things that are really useful so we don't have to actually deal with them and then what I can do is a gap two and here I can Target my container the opacity I can put it to zero and when that is done I can do a then trigger function and only after that do I want to set the display of the new page and so we can try this out I'm going to go to the homepage I'm going to refresh and now you're going to see that it's a bit weird it's triggering as soon as the page load it's triggering that used Gap because we're setting the children with an initial value and so that used Gap here is getting triggered and then it's just fading out the container right and so how to fix that we basically need to check only if the children has changed do we want to do an exit animation we don't want to do it initially so for that in the component here I'm going to add a key to each page so that I can actually identify and differentiate them so here I'm going to grab the router it's actually a prop that we have access here and all I can do is do router. route and now I can do an if children. key is not equal to the display children. key then I want to create my exit animation and so the meaning of that is are we in a different page than the one that we were at the initial load so let's see what that means inside of the actual app if I'm in a home my children here is the home and my display children is also the home that's on the initial load and let's say I decide to go on the about page right now I'm on the about page my children changes but my display children is still set to the homepage so now the key are different and so now it's going inside of that code right that's a bit of the logic and so that's what we see here I'm in the home going into the about page it's fading out and I'm in the about page and obviously I've put the opacity to zero so I don't see anything and to fix that all I have to do is after I set the children I can do a gap 2 and I can reset the opacity of the container back to one so let's say I'm in the homepage go into the about page and now I have a nice fade in and Fade Out and to me that looks pretty good now this is a very simplified version I want to bring this to some other level so that we can actually use this in the real world app all right the first thing that I don't like with this is if I scroll you're going to see I'm in the homepage now I'm scrolling going to the about page you see this it's scrolling up and then it's fading out and then we have the page right and to me it's itching my eye a bit I don't like this scrolling up and after that it's doing the exit animation right and it's actually the normal behavior of the browser all right every time we change the route it's going to scroll to the top so that we're at the top of the next page but since we're hijacking the display of the page it looks a bit weird like that so to fix that all we have to do is inside of our link component next just actually thought about that and all we can do is specify that we do not want to scroll here so I'm going to do scroll false and now what we're going to have here I'm going to scroll and you see here that there is no scrolling when I change my page now but obviously it's not good because it's not scrolling to the top so it's keeping the past scrolling data from the past page right so it's not the best and to fix that all I have to do here is after I set the display of my children just before doing the enter animation here with The Gap 2 I'm going to do a window. scroll two and I'm just going to scroll to the top of the page like this and so now I'm in the projects go to the home I'm going to scroll and that looks pretty nice to me and now with this we actually have another problem all right if I refresh my page here you're going to see I actually don't have an entry animation on my initial page I only have an entry animation when I change my page right because this code here is getting triggered only when there is a change of page so very simple what I can do is do a use Gap and here with empty dependencies so it's going to get triggered once initially and I can just grab this code here set the container to opacity one and I could have the initial style here set to opacity zero something like that and now I have an initial fade in on my first load and I still have my page transition so that's that's a basic fade in and fade out but obviously I'm still not satisfied with that I wouldn't use that solution in the real world app it's like an easy solution though it would work but in a real world case what's really going to happen is we're not going to have a simple fade in and fed out animation a lot of times what we want to have is an animation specific to the page so if I look at the final result here you're going to see that in my homepage I have some Translate animation with some fade in in my about page I have a and in my projects it's coming from the left right it's a very simplified idea but still conceptually it's really important because if you look at like most Awards winning websites they have a lot of fancy animation on the landing section and those Landing animations are different from each page so this current setup don't really support that because it's kind of separated from the content of each page right it's like wrapping it and all we're doing is changing the opacity of a parent so we have no control over the actual content of a page that's why I need to tweak this solution to make it even better to allow a specific animation for each page and so it's going to get a bit more complicated what we're going to have to do is create a context using the context API and I'm going to have like a global State and inside of that Global State I can actually speak from my page to it and inside of my transition rapper I can speak to it as well so let's see how we can do this so like I said I need to start using the context API so the first thing that I'm going to do is create inside of my Source folder here I'm going to have a context folder and inside of that I could have all of my different providers but for now I'm just going to have one and it's going to be the transition context and inside of it I'm going to have a basic react app but I'm actually going to change it it's going to be actually a const here and I'm going to have a transition provider equal like this and I'm actually going to have another thing it's going to be the const transition context and here it's going to be equal to the create context and it's just going to be an N op object for now and now this transition provider instead of returning a div here I'm going to return a transition context. provider and inside of it I'm going to have the children now all of this might be a bit complicated if you don't know about the context API but I highly recommend you check it out I don't want to spend too much time explaining it it's basically a state that's Global and this is just a bit of details so here it's taking the children as a props and then I'm just going to export the transition context and the transition provider here so that's like the base structure of a context and a provider and inside of my app instead of having fragments here I'm going to have my transition provider going to take that put it here something like this so now all of my components that are wrapped inside of my transition provider now have access to the context and now obviously there are no values that are defined here and so it's quite useless so I'm going to define a value here and so this is going to be a state and inside of the state what I'm GNA have is a timeline all right I'm gonna create a gsop timeline so here I'm going to have the timeline and the set timeline it's going to be equal to a state and here I can initialize a function and it's basically going to return me a gap. timeline and I'm going to have it paused true at first and then the value of my context is going to be that timeline and I can also do set timeline here oh now Gap I need to import it so import Gap from Gap and with that what I did is I created a gap timeline that is now available for all of the children inside of my app and now inside of that timeline I can add my entry and exit animation that are specific to the current page all right that's basically why I'm creating a context and so now I'm going to overwrite the way I did my entry and exit animation and I'm going to use the timeline instead so I'm going to go back into my transition here and I'm going to start by deleting here my entry animation because I don't really like this way of doing things I'm actually not going to need the ref anymore as well so I'm taking that out and here I'm actually going to comment out that and I'm just going to keep the set display children here to have the basic routing structure and if I save that I should have something like a basic routing and that's good so now we're back at zero but I'm going to use the timeline so I'm going to go for example in the homepage and now I'm going to do something similar that I had inside of the transition wrapper I'm going to have the Gap I'm going to import Gap from Gap I'm going to import the use Gap as well and actually this time I'm going to add a scope and I'm going to have a container as the scope and I'm just going to explain to you what it is I'm going to create here the container it's going to be a ref and here I'll give the parent of the page that container and so now all of my codes for example some query selectors or things like that inside of that hook will be scoped inside of that container here so what that means is if I do a query selector and I select all the paragraphs for example it's only going to select the paragraphs that are inside of the container nothing outside of it so it's a nice way of containing and making sure we don't have conflicts between our other components other pages so now let's say I want to have an initial animation for the first load well I'll do the same thing that I had before gab 2 and I can Target my container opacity to one actually I'm going to do opacity zero and here I'm going to do opacity one and I'm going to have a from Two and so here if I refresh I have a nice initial animation and now let's say I want to have my exit animation right now the context API com in what I'm going to have here is the timeline that's going to be coming from the use context and here I'm going to grab my transition context and so now this timeline is coming from the timeline that is inside of that transition context and so now I'm going to add it an exit animation and so let's see what I could create for an exit animation for now I'm just going to do like a fade out just really to keep it simple so I'm going to do timeline and I'm going to add an animation to it and I'm going to add a gap to I'm going to do container. current and I'm going to animate out the opacity like this so now I've added an animation inside of my timeline on exit now obviously it's not going to work I need to find a way to trigger it and that's where we return inside of the transition Rober here and here it's nice I also have access to my timeline which is coming from the use context same thing here of the transition context and now instead of kind of hard coding a gab 2 what I'm going to use is the animation in ins side of my timeline so I can just do play like this and then I can do a then similar to what I had and here I'm going to grab the same thing but I'm going to take the Gap 2 out here so now I have a set display children a scroll and I'm just going to add an extra thing here just to make sure there are no bugs I'm going to do a timeline I'm going to do a pause and I'm going to do a clear so what's happening here is we're playing the animation that we just added inside of a timeline right inside of a homepage we've added a gap 2 and that's our exit animation and so now when the page changes we access that timeline we play that exit animation and yeah we do the same thing that we did before and just to make sure that there are no problems we pause the timeline and we clear it so now I can delete this here I'm going to save it so let's see what we have I'm in the homepage going to the about page I have a nice exit animation and now obviously my about page here is not animated so all I have to do is take the same logic that I've created here for my homepage and apply it to my projects page and my about page P so I'm going to do this now okay so I've just added the same code that I had inside of my index but now I have it inside of my projects page and my about page and so what we have is if I go into my about and projects page now everything is working good I have a nice fade in Fade Out a bit similar to what we had a couple of minutes ago but now we actually have way more control over one or entry animation and also our exit animation we can create a way more customized page transition which is really nice and a much more abstract approach that's more flexible so let's try an example I'm going to go into my homepage and let's say I want to have a more of a fancy entry animation right I'm going to have my targets I'm going to create here just a bunch of targets which would be all of the elements that I want to animate and here I can do a gstop I think it's UT tails. to array and I'm going to add inside of an array all the paragraphs of my page and here I'm also going to add to that array um an image and it's going to be an image. current and so here I'm going to create a ref it's going to called be called image and then the image container I can give it that image ref and so now my targets are all of my paragraphs and my image and so I can give that targets to the from 2 and so now I'm going to grab my targets here and here to make the opacity one by one I can simply add which is really nice in gap a stagger and I can do like Zer oh not minus but 0.1 okay so this is not working I believe my two array here I need to put this inside of an array like this just to make sure everything works good and yeah if I refresh you see that I have a nice customized entry animation for that page and I could make it a bit more fancy and add like a y translation so 30 initially and then I'm going to reset it back to zero and so now I have a nice fade in animation looks really cool and so that's for the homepage and I could do the same logic I'm just going to copy paste that go inside of my projects page for example and now inside of my projects page instead of changing let's see the Y I'm going to for example change the scale so I'm going to do scale 0.8 and it's going to be be reseted back to one and so now homepage is a y translation and projects page is a scaling right and I'm keeping just the fade out for the exit animation on both page but I could have like way more fancy stuff but personally for the exit animation I like to keep it simple and now for the about page maybe instead of doing the scale what I'm going to do is do a x and I'm going to do minus 30 and then X I'm going to reset it back to zero so a x translation and if I refresh I'll not have a nice little animation for the about page and so yeah a nice page transition with crazy control over the actual content of the page something like this and even if I scroll everything looks nice so this is actually something that I would personally use inside of a real world project so yeah hope you guys learned something um also if you prefer to use maybe frame motion to create your page transition I have a bunch of videos on that as well you can check it out because I would personally always use frame motion over Gap probably inside of a react app unless the client specifies that I need to use gap or maybe my teammates and my co-workers they prefer to use Gap than I wouldn't mind using GAA but personally I would probably use frame motion but yeah anyways if you like the video leave a like subscribe and I'll see you in the next one bye
Info
Channel: Olivier Larose
Views: 12,727
Rating: undefined out of 5
Keywords:
Id: vqMRNEPEzlQ
Channel Id: undefined
Length: 21min 37sec (1297 seconds)
Published: Sun Mar 31 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.