Free YouTube Transcribe

Video transcript

Next JS Page Transitions Just Got a Whole Lot Cooler (SVG Domination)

Codegrid · 2,314 words · 11 min read

Want to search this transcript, jump the video from any line, or download it as TXT, SRT, or VTT?

Open in the transcript tool

Full transcript

Intro

0:00It has been a while since we last

0:01explored a fresh page transition concept

0:04here on the channel as I've been

0:05focusing quite a lot on scroll

0:07animations for the past few months.

0:09[music]

0:09Now, for those of you who have been

0:11keeping an eye on things, you might

0:13remember that around two months ago, I

0:15covered this really cool SVG powered

0:18image hover effect and ever since

0:19putting that together, I knew the same

0:22technique had a lot of potential beyond

0:24just hover interactions. So, last

0:26[music] weekend, I took those same SVG

0:28elements and repurposed them into a full

0:31page transition effect using [music]

0:32Next.js and GSAP. As you can see here,

0:35every time I navigate between routes,

0:37the SVG strokes draw in and fill the

0:40entire screen to cover the current page

0:42and then continue forward off the other

0:44side to reveal the new one underneath.

0:46It creates this really fluid vibe that

0:48feels organic and hand-drawn compared to

0:51the typical slide or fade transitions.

0:53In this video, I'm going to walk you

0:55through how to build this step-by-step

0:58using Next Transition Router and GSAP.

1:00We'll set up the transition provider,

1:02wire in the SVG paths, and then animate

1:04them with the stroke dash offset

1:06technique to get this effect working

1:08across all your routes. If you'd like to

1:10access the source code for this project

1:12along with hundreds of other similar

1:14micro projects and a brand new website

1:16template every month, you can check out

1:18the pro membership via the link in the

1:19description. And if you find my work

1:21helpful, make sure you leave a like on

1:23the video and subscribe to the channel

1:25if you haven't already. All right, let's

1:27get into the code. [music]

Project Setup Walkthrough

1:30Just to save some time, I've already set

1:32up a few placeholder pages along with a

1:34navigation bar and some basic styling.

1:36[music] Let me quickly walk you through

1:38what I have so far. There are three

1:40pages: home, about, and contact. Each

1:42one is pretty straightforward, just a

1:44section with a class of hero and an H1

1:47inside it. For the navigation, I have a

1:49navbar component using Next.js link

1:51components instead of regular anchor

1:53tags. The reason for that is link

1:56handles client-side navigation, meaning

1:58the page does not do a full reload when

2:00you click a link. because our transition

2:03effect later will depend on intercepting

2:05that navigation. The navbar itself has a

2:07logo on the left linking back to home

2:10and three page links on the right.

2:11[music] Now, in the root layout, the

2:13navbar is rendered right before

2:15children. Since the layout component

2:17wraps every route in the app, this means

2:19the navbar stays mounted across page

2:21changes and does not unmount and remount

2:23every time I navigate. I've also set up

2:26a few fonts using the Next.js font

2:28module. What this does is it downloads

2:30and self-hosts the font files at build

2:32time, so there are no external requests

2:35to Google Fonts at run time. It exposes

2:38them as [music] CSS custom properties,

2:40which I can then use anywhere in my

2:41style sheet. On the styling side, I've

2:44defined a couple of custom properties on

2:46the root for the background and

2:47foreground colors, so the palette is

2:49controlled from a single place. The

2:51navbar is fixed positioned, so it sticks

2:53to the top of the viewport and flexbox

2:56handles the spacing between the logo and

2:58the links. The hero section is set to

3:00100 viewport height. The content is

3:01centered with flexbox and the H1 uses

3:04clamp for a fluid font size that scales

3:06between mobile and desktop without any

3:08media queries. With all of that in

3:10place, I have the dev server running and

3:12as you can see here, clicking through

3:14the navbar links swaps between pages.

3:17Right now, there is no transition at

3:19all. The pages just cut instantly. So,

3:21let's start building that out. The first

Installing Dependencies

3:24thing we need to do is install the

3:25packages we'll be using. I will open up

3:27the integrated terminal and install GSAP

3:30along with Next Transition Router. GSAP

3:33is what we'll use to animate the SVG

3:34strokes and Next Transition Router is

3:37what lets us hook into Next.js page

3:39navigations and run custom animations

3:41during route changes. Now, with those

Creating the TransitionProvider

3:43installed, we need a provider component

3:46that will handle the page transition, so

3:48I'm going to create a new folder called

3:50providers inside the source directory

3:52and inside that, let's create a new file

3:54called Transition Provider. This

3:56component is going to be responsible for

3:58intercepting page navigations and

4:00running our SVG animation before and

4:02after each route change. Now, first

4:04thing at the top, I need to add the use

4:06client directive. This is required

4:08because the transition logic involves

4:10refs, effects, and browser APIs, which

4:13only run on the client side. Then, I

4:15will import the transition router from

4:17Next Transition Router. This is the

4:19package that does the heavy lifting for

4:21us. It hooks into Next.js client-side

4:23routing and gives us leave and enter

4:25callbacks where we can run whatever

4:27animation we want before the old page

4:29unmounts and after the new page mounts.

4:31Now, for the component itself, I will

4:34export a default function called

4:35Transition Provider that accepts

4:37children as a prop. Inside it, for now,

4:40we'll just return Transition Router with

4:42the auto prop and wrapping children

4:44inside it. The auto prop tells

4:46Transition Router to automatically

4:48intercept any Next.js link navigations

4:50in the app, so we do not have to

4:52manually trigger transitions ourselves.

4:54Children is whatever page content gets

4:56passed through from the layout. Now, we

4:58need to actually use this provider. So,

5:00back in the root layout, we need to

Wiring into Layout

5:02import Transition Provider from the

5:04providers folder and then wrap children

5:06with it right below the navbar. Now, let

5:08me go back to the Transition Provider.

5:10What we need to do next is add the SVG

Adding SVG Paths

5:13that will act as our transition overlay.

5:15This is what will visually cover the

5:16screen during the page change. So, right

5:18above children, I'll create a new div

5:20with the class of transition SVG. This

5:23div is going to be the container that

5:25holds our SVG and sits on top of

5:27everything as a fixed overlay. Inside

5:29that, I placed in an SVG element with

5:32two path elements. These paths are

5:33basically hand-drawn looping bezier

5:35curves that zigzag across the canvas.

5:38The view box is set to match the

5:39coordinate space that the paths were

5:41designed in and I have set preserve

5:43aspect ratio to none, which is important

5:45because it allows the SVG to stretch and

5:47fill the entire viewport regardless of

5:49the screen's aspect ratio. Each path has

5:52a stroke color referencing a CSS custom

5:54property, a stroke width of 200, and

5:57stroke line caps at two round for smooth

5:59ends. Now, let me get the styling done

Styling the SVG Overlay

6:01for this. First of all, I'll define the

6:04two stroke color variables on the root.

6:06I'm setting transition stroke one to

6:07this orange and transition stroke two to

6:10this purple. Having these as custom

6:12properties means I can easily swap the

6:14colors from one place without touching

6:16the component. Then, for the transition

6:18SVG container itself, I'm setting it to

6:21fixed positioning, so it stays locked to

6:23the viewport and does not scroll with

6:25the page content. Top 50% and left 50%

6:29along with the translate minus 50 on

6:31both axes centers it perfectly in the

6:33viewport. The scale 1.5 on the transform

6:36is key here. It over scales the SVG

6:38slightly, so the strokes will be covered

6:40every edge of the screen when they

6:42expand. Width and height are both 100%

6:45to fill the viewport and pointer events

6:47is set to none, so the overlay does not

6:49block any clicks or interactions with

6:51the page underneath. We also set a high

6:53z-index to make sure it sits above

6:56everything else. Next, for the SVG

6:58itself inside the container, I'm just

7:00setting width and height to 100%, so it

7:02fills its parent completely. And

7:05finally, on the path elements, I'm

7:07setting stroke dash offset and stroke

7:09dash array both to a high value. This is

7:11a CSS-only safeguard to make sure the

7:13paths are hidden on the initial page

7:15load. Without this, you might see an

7:17artifact before the JavaScript runs

7:19where the raw SVG strokes would flash on

7:22the screen. Setting a huge dash offset

7:24like this effectively hides them from

7:26the start and then once our use effect

7:29kicks in, it will replace these with the

7:31actual calculated values. With that in

7:33place, in the next step, we'll set up

7:35the JavaScript side to properly measure

7:37the path lengths and wire up the

7:39transition animations. All right, so now

7:41we need to set up the refs and the use

7:43effect that [music] will measure our SVG

7:45paths. To do that, I'll first import use

Measuring Path Lengths

7:48ref and use effect from React. Then,

7:50inside the component, I'll create two

7:52refs. SVG ref is going to hold a

7:54reference to the SVG element itself and

7:57paths ref will store an array of the

7:59individual path elements inside it. The

8:01reason I'm using a ref for the paths

8:03array instead of state is because we do

8:06not need React to re-render when this

8:08value changes. We just need a persistent

8:11reference that GSAP can access later

8:13during the animations. Now, to actually

8:15connect SVG ref to the SVG element, I

8:18will go ahead and set the ref on the SVG

8:21tag. With that in place, we can now set

8:23up the use effect. This is where we

8:25measure the paths and set up the initial

8:27dash values that make the stroke draw

8:29technique work. So, first thing inside,

8:31we are doing a quick guard check. If SVG

8:33ref does not exist for whatever reason,

8:36we just bail out early. After that, we

8:39grab all the path elements from the SVG

8:41using query selector all and convert

8:43that node list into an array, so we can

8:46store it in the paths ref. Now comes the

8:48important part. We loop through each

8:50path and call get total length on it.

8:53This is a native SVG method that returns

8:55the exact pixel length of the particular

8:57path and since both of our paths have

9:00different curves, they will each have a

9:02different length. Once we have that

9:03value, we set both stroke dash array and

9:06stroke dash offset to that length. So,

9:08what this does is it creates a single

9:10dash that spans the entire path, but

9:13offsets it by its full length, which

9:15effectively hides the stroke completely.

9:17And this replaces the large values we

9:19set in CSS earlier with the actual

9:21precise measurements. All right, so now

9:23that the paths are measured and hidden,

Animating the Leave Transition

9:26it is time to bring in the animation.

9:28So, I'll go ahead and import GSAP at the

9:30top. The first animation we need is the

9:33leave transition, which is what runs

9:35when the user clicks a link and the

9:36current page is about to exit. So,

9:39Transition Router gives us a next

9:41callback here and we have to call it

9:43when our animation finishes, so it knows

9:45when to actually swap the page content.

9:47With that in mind, we are creating a

9:49GSAP timeline and setting on complete to

9:51next. That way, the page swap happens

9:54automatically once the animation is

9:56done. Then, we loop through each path

9:58and add a tween to the timeline. What we

10:00are animating here is stroke-dashoffset

10:02down to zero, which draws the stroke in

10:05from fully hidden to fully visible. And

10:07at the same time, we are also animating

10:09stroke width attribute from 200 up to

10:11700 using the attribute object. This is

10:15really the trick that makes the whole

10:17effect work. As the stroke draws in, it

10:19also gets thicker. And because these

10:21paths loop and crisscross across the

10:24entire view box, a stroke width of 700

10:26is more than enough to completely fill

10:28the screen with color. Finally, I'm

10:30returning a cleanup function that kills

10:33the timeline, which just prevents any

10:35issues if the component happens to

10:37unmount while the animation is still

10:38running. Now for the enter transition,

Animating the Enter Transition

10:41which runs right after the new page is

10:42mounted, and we need to reveal it by

10:44clearing the SVG overlay. So, same

10:46structure here. We create a timeline

10:49with on complete calling next. We then

10:51loop through the paths, but this time I

10:53first need to grab each path's total

10:55length again. And here is where it gets

10:57interesting. Instead of animating

10:59stroke-dashoffset back to the positive

11:01length, which would just reverse the

11:03stroke back the way it came in like a

11:05rewind, we need to animate it to a

11:07negative length. What the negative value

11:09does is it pushes the dash forward past

11:12the end of the path. So, visually it

11:14looks like the stroke is continuing its

11:16journey off the other side of the

11:18screen, rather than shrinking back to

11:20where it started. That gives it a much

11:23more fluid and natural feel. Along with

11:25that, I'm bringing stroke width back

11:27down to 200, so the strokes thin out as

11:30they exit. Now, once each path finishes

11:33its animation, we are using GSAP's set

11:35method right away to reset

11:37stroke-dashoffset back to the positive

11:39length. This step is critical because it

11:41puts everything back to its initial

11:43hidden state, ready for the next time

11:45someone navigates. And same as before,

11:48we return a cleanup function to kill the

11:49timeline. And that's pretty much it. As

Final Result

11:52you can see, clicking through the pages

11:54now triggers this SVG stroke wipe that

11:56draws in to cover the old page and then

11:58continues forward to reveal the new one

12:00underneath. Hope you found the video

12:02helpful. Thanks for watching, and I'll

12:04see you in the next one.

More from Codegrid

Recently added transcripts

Browse the whole transcript library

This transcript was generated from the captions YouTube publishes for this video. Get the transcript of any YouTube video atfreeyoutubetranscribe.com, free, unlimited, no sign-up.