ReactHustle

How to Implement Transitions in Next.js App Router Using useTransition

Jasser Mark Arioste

Jasser Mark Arioste

How to Implement Transitions in Next.js App Router Using useTransition

Next.js provides powerful tools for creating seamless user experiences, and one such feature is the useTransition hook from React. By implementing a transition system, you can visually indicate page navigation progress, enhancing user interaction. This article demonstrates how to set up transitions in a Next.js application using the app router.

Prerequisites #

Before you begin, ensure the following:

  1. React and Next.js versions:React 18.0 or later (for useTransition support).Next.js 13.4 or later (for the app router).
  2. React 18.0 or later (for useTransition support).
  3. Next.js 13.4 or later (for the app router).
  4. Installed Tailwind CSS (optional): The example includes styling using Tailwind CSS.

Demo #

Setting Up Transition Context and Components #

Here’s a step-by-step guide to implementing a transition system in your Next.js application.

1. Create the Transition Context

The transition context will manage the state of transitions globally.

"use client";

import { createContext, ReactNode, useContext, useTransition } from "react";

// Define the type for the transition state
type State = {
  isPending: boolean;
  startTransition: (callback: () => void) => void;
} | null;

// Create a context for transitions
const TransitionContext = createContext<State>(null);

export function TransitionProvider({ children }: { children: ReactNode }) {
  const [isPending, startTransition] = useTransition();

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

export const useGlobalTransition = () => {
  const context = useContext(TransitionContext);
  if (!context) {
    throw new Error(
      "useGlobalTransition must be used within a TransitionProvider"
    );
  }
  return context;
};
1234567891011121314151617181920212223242526272829303132

2. Add a Loading Indicator Component

The loading indicator provides visual feedback to users during transitions.

export function LoadingIndicator() {
  const { isPending } = useGlobalTransition();

  return (
    <div
      className={`fixed top-0 left-0 w-screen h-1 bg-teal-500 z-50 transition-opacity duration-300 ${
        isPending ? "opacity-100" : "opacity-0"
      }`}
      role="progressbar"
      aria-valuetext={isPending ? "Loading" : "Loaded"}
    >
      <div className="h-full w-full bg-white animate-loading"></div>
    </div>
  );
}
123456789101112131415

3. Create the Transition Link Component

The TransitionLink component wraps Next.js’s Link and integrates the transition logic.

import Link, { LinkProps } from "next/link";
import { useRouter } from "next/navigation";
import { PropsWithChildren } from "react";

export function TransitionLink({
  href,
  ...props
}: LinkProps & PropsWithChildren) {
  const { startTransition } = useGlobalTransition();
  const router = useRouter();

  return (
    <Link
      {...props}
      href={href}
      onClick={(e) => {
        e.preventDefault();
        startTransition(() => {
          router.push(href.toString());
        });
      }}
    />
  );
}
123456789101112131415161718192021222324

4. Add Styles for the Loading Indicator (Optional)

If you’re using Tailwind CSS, add the following animation to your tailwind.config.js file:

module.exports = {
  theme: {
    extend: {
      animation: {
        loading: "loading 1.5s infinite",
      },
      keyframes: {
        loading: {
          "0%": { transform: "translateX(-100%)" },
          "100%": { transform: "translateX(100%)" },
        },
      },
    },
  },
};
123456789101112131415

5. Wrap Your Application with the Transition Provider

Wrap your app in the TransitionProvider in the layout.tsx file.

import { TransitionProvider } from "./path/to/TransitionProvider";
import { LoadingIndicator } from "./path/to/LoadingIndicator";

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <TransitionProvider>
          <LoadingIndicator />
          {children}
        </TransitionProvider>
      </body>
    </html>
  );
}
123456789101112131415

6. Use the Transition Link Component

Replace standard Link components with TransitionLink wherever you want the transition effect.

import { TransitionLink } from "./path/to/TransitionLink";

export default function ExamplePage() {
  return (
    <div>
      <h1>Welcome to the Transition Example</h1>
      <TransitionLink href="/next-page">Go to Next Page</TransitionLink>
    </div>
  );
}
12345678910

Conclusion #

Using useTransition and a custom context, you can create a seamless navigation experience in your Next.js application. The approach outlined above enhances user interaction with visual feedback during page transitions. Tailor the loading indicator's appearance and behavior to match your application's branding and requirements.

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle