Frontend Development 17 min read

Implementing High-Performance Page Transition Animations in Next.js with HTML View Transition API and React startTransition

This article explains how to create smooth, high‑performance page transition animations in Next.js by combining the native HTML View Transition API with React 18's startTransition, covering usage for both Link component navigation and browser back/forward actions, and providing complete code examples and best‑practice analysis.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing High-Performance Page Transition Animations in Next.js with HTML View Transition API and React startTransition

A community member posted a site with a page‑transition animation and asked: How to implement page‑switch transition animations in a Next.js project? As a developer who often writes Next.js tips, I decided to explore this problem and share a solution that leverages the browser's native HTML View Transition API together with React 18's startTransition for optimal performance.

After testing several approaches, I chose the most performant one: combining the HTML View Transition API with React.startTransition . This method uses the browser's built‑in capabilities for smoother animations and lets React schedule low‑priority UI updates, keeping the interface responsive.

By the end of this article you will learn:

How to use the HTML View Transition API.

How to use React startTransition .

A hand‑crafted, high‑performance solution for page‑switch transition animations.

An analysis of a comparable open‑source solution and its best practices.

HTML View Transition API Usage Introduction

The View Transition API is a newly released HTML feature that enables smooth transition effects when a page changes state or navigates to a new page, providing a more fluid user experience.

Before this API, developers had to rely on JavaScript and CSS to create transitions. With the native API, the code becomes simpler and performance improves.

Basic Usage of the View Transition API

The API can be used in two scenarios: Single‑Page Applications (SPA) and Multi‑Page Applications (MPA).

For SPAs:

if (document.startViewTransition) {
  document.startViewTransition(() => {
    // Update DOM here
    updateDOM();
  });
} else {
  // Fallback for browsers that do not support the API
  updateDOM();
}

For MPAs:

@view-transition {
  navigation: auto;
}

Beyond the basics, developers can customize transition effects, target specific elements, and control the transition flow, but those details are beyond the scope of this article.

React startTransition Usage Introduction

startTransition is a new feature introduced in React 18. It allows developers to mark certain state updates as "transitions" (low priority). While a transition is pending, higher‑priority updates such as user input are processed first, ensuring UI responsiveness.

Basic Usage of startTransition

Below is a simple tab‑switch example that uses startTransition :

import React, { useState, startTransition } from 'react';

function TabContainer() {
  const [tab, setTab] = useState('about');

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
selectTab('about')}>About
selectTab('posts')}>Posts
selectTab('contact')}>Contact
{tab === 'about' &&
}
      {tab === 'posts' &&
}
      {tab === 'contact' &&
}
);
}

Hand‑crafted High‑Performance Page‑Switch Transition Solution

To implement transition effects we need to consider two scenarios:

Navigation via the <Link> component.

Browser back/forward navigation.

Overriding <Link> Navigation

Next.js wraps the native <a> tag with its own <Link> component, handling navigation via onClick and the History API. We can intercept this click, invoke document.startViewTransition , and then perform the navigation.

File: components/TransitionLink.tsx

"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React from "react";

const TransitionLink = ({ href, children, ...props }) => {
  const router = useRouter();

  const handleClick = (e) => {
    e.preventDefault();
    console.log('Intercepted navigation');
    if (document.startViewTransition) {
      document.startViewTransition(() => {
        router.push(href); // Simplified; replace handling omitted for brevity
      });
    } else {
      router.push(href);
    }
  };

  return (
{children}
    
  );
};

export default TransitionLink;

Replace every usage of <Link> with <TransitionLink> to get a basic transition effect. To make the effect more noticeable, adjust the global CSS transition duration:

:root {
  --view-transition-duration: 1s;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--view-transition-duration);
}

Overriding Browser Back/Forward Transitions

Back/forward navigation does not have a dedicated component, so we create a context that wraps the whole app and a hook that rewrites the popstate event to trigger document.startViewTransition .

File: components/TransitionProvider.tsx

"use client";
import React, { createContext, useContext } from "react";
import useSimplifiedViewTransition from '@/hooks/useSimplifiedViewTransition';

const TransitionContext = createContext(null);
export const useTransitionContext = () => useContext(TransitionContext);

export const TransitionProvider = ({ children }) => {
  useSimplifiedViewTransition(); // Attach popstate listener
  return (
{children}
);
};

Hook: hooks/useSimplifiedViewTransition.ts

import { useEffect } from 'react';

export default function useSimplifiedViewTransition() {
  useEffect(() => {
    if (!document.startViewTransition) {
      console.log('Browser does not support View Transitions API');
      return;
    }
    const handlePopState = () => {
      console.log('View transition triggered');
      document.startViewTransition(() => {
        console.log('startViewTransition');
      });
    };
    window.addEventListener('popstate', handlePopState);
    return () => window.removeEventListener('popstate', handlePopState);
  }, []);
}

In the app layout, wrap the page tree with <TransitionProvider> so that every route change, including back/forward actions, can trigger the transition.

Best‑Practice Source Analysis

Examining the open‑source next-view-transitions library reveals a more complete implementation. The core Link component adds API‑availability checks and integrates React.startTransition with a custom context to resolve the transition promise.

Key snippet from the library:

import NextLink from 'next/link';
import { useRouter } from 'next/navigation';
import { startTransition, useCallback } from 'react';
import { useSetFinishViewTransition } from './transition-context';

export function Link(props) {
  const router = useRouter();
  const finishViewTransition = useSetFinishViewTransition();
  const { href, as, replace, scroll } = props;

  const onClick = useCallback((e) => {
    if (props.onClick) props.onClick(e);
    if ('startViewTransition' in document) {
      e.preventDefault();
      document.startViewTransition(() =>
        new Promise((resolve) => {
          startTransition(() => {
            router[replace ? 'replace' : 'push'](as || href, { scroll: scroll ?? true });
            finishViewTransition(() => resolve);
          });
        })
      );
    }
  }, [props.onClick, href, as, replace, scroll]);

  return
;
}

This implementation mirrors the hand‑crafted solution but adds robust handling for replace navigation, scroll behavior, and a promise‑based completion callback.

Conclusion

Combining the HTML View Transition API with React startTransition provides a native, high‑performance way to add page‑switch animations in Next.js without extra dependencies. This approach yields the best possible performance and a smoother user experience.

About the Author

I am a frontend engineer specializing in Next.js and Node.js, actively contributing to open‑source projects and sharing knowledge in the community.

frontend developmentNext.jsPage AnimationReact startTransitionView Transition API
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.