Logo
Published on

How to show a Loading Indicator on route change in NextJS 13/14 App Router

Authors
  • avatar
    Name
    Rohan Hussain
    Twitter

Once you've followed this guide, when a user clicks a button or link that initiates a route change, an NProgress loading indicator will show up instantaneously on the top of the viewport just under the address bar.

Expected Result

You'll see a snake-like loading indicator under the browser address bar, similar to the one on educative.io: Educative Loading Indicator You'll be able to style it as per your theme.

Install npm backage

We will use the nextjs-toploader npm package which is fairly popular. As of this moment, it has 46k weekly downloads.

# npm
npm install nextjs-toploader

# yarn
yarn add nextjs-toploader

# pnpm
pnpm install nextjs-toploader

# bun
bun install nextjs-toploader

Add NextTopLoader to your root layout.tsx

Go to your /app/layout.tsx or /src/app/layout.tsx and add the following to your root layout component's returned JSX:

import NextTopLoader from "nextjs-toploader";

export default function RootLayout() {
    // component body

    return (
        <div>
            {/* other stuff */}

            {/* Add this line */}
            <NextTopLoader />
        </div>
    );
}

Note that you do NOT need to turn your root layout into a client component with use client to make this work. This works with server components as well.

That's it. You're done.

How to customize styling

As per the library's current npm page, the following are the default values of the props that this component takes:

export default function RootLayout() {
    // component body

    return (
        <div>
            {/* other stuff */}

            {/* Add this line */}
            <NextTopLoader
                color="#2299DD"
                initialPosition={0.08}
                crawlSpeed={200}
                height={3}
                crawl={true}
                showSpinner={true}
                easing="ease"
                speed={200}
                shadow="0 0 10px #2299DD,0 0 5px #2299DD"
                template='<div class="bar" role="bar"><div class="peg"></div></div> 
                <div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
                zIndex={1600}
                showAtBottom={false}
            />
        </div>
    );
}

showSpinner is true by default and shows a loading spinner on the top right corner of the screen while loading is in progress.

You can override any of these selectively, for example:

import NextTopLoader from "nextjs-toploader";

export default function RootLayout() {
    // component body

    return (
        <div>
            {/* other stuff */}

            {/* Add this line */}
            <NextTopLoader color="#FFFFFF" shadow={false} showSpinner={false} />
        </div>
    );
}