# next-view-transitions: CSS View Transitions for the Next.js App Router

> A small MIT-licensed wrapper that wires the browser View Transitions API into App Router navigation. It covers basic route transitions well, and its own README says complex rendering cases still need work in React and Next.js.

**shuding/next-view-transitions** — Use CSS View Transitions API in Next.js App Router.

- Repository: https://github.com/shuding/next-view-transitions
- Website: https://next-view-transitions.vercel.app
- Stars: 2,386 · Forks: 93
- Language: TypeScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/shuding-next-view-transitions

## The problem: App Router navigation swaps content with no visual continuity

Client-side navigation in the Next.js App Router replaces the rendered tree instantly. The URL changes, the new route paints, and there is no browser-level animation connecting the two states. Developers who want a crossfade or a shared-element move normally reach for a motion library, which means wrapping route content in animation components and managing enter and exit states by hand.

next-view-transitions takes a different route. It exposes the browser's View Transitions API to App Router navigation, so the browser itself captures the old view, captures the new one, and animates between them. The package is TypeScript, MIT licensed, and published from a repository whose top-level entries are a src directory, an example directory, and the usual package and lock files. Its peer dependencies are next >=14.0.0 and react and react-dom >=18.2.0 || ^19.0.0, which tells you the intended audience: teams already on the App Router, not Pages Router holdouts.

The README is explicit about the ceiling. It says the library is aimed at basic use cases, and that concurrent rendering, Suspense and streaming need new primitives in React and Next.js before they work properly. That sentence should shape your evaluation more than any feature list.

## How the ViewTransitions wrapper and its Link component work

The mechanism is a wrapper plus a navigation hook. You place the ViewTransitions component around your document inside the layout file, and it sets up the browser-side transition plumbing for everything rendered beneath it. Navigation then has to go through the package's own primitives rather than next/link, because the transition has to be started around the route change.

The package ships two entry points for that. The Link component is a drop-in replacement for the App Router link for anchors that should animate. The useTransitionRouter hook returns a router whose methods, per the README, match the Next.js router methods, so router.push('/about') triggers a transition rather than a plain navigation. The data flow is therefore: user activates the link or calls a router method, the package starts a view transition, Next.js completes the route change, and the browser animates between the captured before and after states.

The build side is small. package.json declares "type": "module", builds with bunchee into ./dist/index.js with types at ./dist/index.d.ts, and publishes only the dist directory. There is no runtime dependency list at all, only devDependencies and peerDependencies, so the installed footprint is essentially the compiled wrapper.

## Install and first transition: a short tutorial

Installation uses whichever package manager you already run. The README shows pnpm:

```bash
pnpm install next-view-transitions
```

After that, wrap the document in your layout file. The README's example places ViewTransitions outside the html element, which is the detail people get wrong most often:

```jsx
import { ViewTransitions } from 'next-view-transitions'

export default function Layout({ children }) {
  return (
    <ViewTransitions>
      <html lang='en'>
        <body>
          {children}
        </body>
      </html>
    </ViewTransitions>
  )
}
```

With the wrapper in place, swap the import for links that should animate. A plain anchor will still navigate, it just will not transition:

```jsx
import { Link } from 'next-view-transitions'

export default function Component() {
  return (
    <div>
      <Link href='/about'>Go to /about</Link>
    </div>
  )
}
```

For navigation triggered by code rather than a click on an anchor, the README gives the useTransitionRouter hook. The returned router supports the Next.js router methods, so existing push, replace and back calls keep their shape:

```jsx
import { useTransitionRouter } from 'next-view-transitions'

export default function Component() {
  const router = useTransitionRouter()

  return (
    <div>
      <button onClick={() => {
        router.push('/about')
      }}>Go to /about</button>
    </div>
  )
}
```

What you should see is a browser-driven animation between the two routes instead of an instant swap. The repository includes an example directory with an app folder and its own package.json if you want a working reference rather than assembling one from the README snippets.

## Where next-view-transitions stops being the right tool

The disclaimer is the honest part of this project. Concurrent rendering, Suspense and streaming are named as cases where the current approach is not sufficient, and the README points to future primitives in React and Next.js core. If your pages suspend while data loads, or stream in sections, the before and after snapshots the browser captures may not represent what the user actually ends up seeing. That is a correctness problem, not a polish problem.

There is a second constraint that follows from the design. Because transitions only happen through the package's Link and useTransitionRouter, any navigation that goes around them, such as a plain next/link or a raw anchor, silently opts out. In a large codebase that means an audit of every navigation call site, and a rule that new code has to follow.

Finally, the README does not document fallback behaviour for browsers without the View Transitions API, nor does it document how to disable transitions for reduced-motion users. Treat both as things you verify in your own setup rather than assume.

## How it differs from a motion library or the native View Transitions API

The closest alternative in spirit is the native View Transitions API used directly. Calling document.startViewTransition around a route change gives you the same browser animation without a package, but you own the integration with the App Router's navigation lifecycle, including making sure the DOM update happens inside the transition callback. next-view-transitions exists to absorb that integration and to keep it current as Next.js changes.

A different alternative is a JavaScript animation library such as Framer Motion, which animates React components you explicitly wrap. That approach gives you per-element control and works with enter and exit states, but it does not use the browser's own snapshot mechanism, so a shared-element transition across two routes requires matching layout identifiers and more code. The trade-off is control against effort: the animation library can express more, and it does not depend on a browser API that the README itself flags as incomplete for streaming cases.

There is also Next's own navigation behaviour to consider. Doing nothing is a legitimate option. If your application is a dashboard where instant swaps are the expected feel, adding a route transition is a preference, not an upgrade.

## Maintenance, versioning and licence implications

The last push to the default branch was on 2026-03-06, and the repository is not archived. The most recent release is 0.3.5, published on 2025-12-05, which followed 0.3.4 on 2024-12-03 and 0.3.2 on 2024-09-22. The version line has stayed in 0.x throughout, so the maintainer has not declared a stable 1.0 API surface. Treat the component and hook names as the practical interface, and expect that a future release could change how the wrapper is placed.

Upgrade cost is low on the surface. There are no runtime dependencies, the published artefact is a single dist entry, and the public API is two exports plus the wrapper. The real cost sits in the peer range: next >=14.0.0 and react and react-dom >=18.2.0 || ^19.0.0. Moving to a Next.js or React major that falls outside that range means checking the package before you upgrade the framework, not after.

The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are preserved. That is a summary of the licence text, not legal advice; your own counsel should review anything you ship.

## Conclusion

Adopt next-view-transitions if you run the App Router, want route-change crossfades with almost no code, and your pages render without heavy Suspense or streaming. Do not adopt it if you need transitions that stay correct during concurrent rendering, or if you cannot accept the README's stated scope of basic use cases. Verify first that your Next.js version meets the >=14.0.0 peer range and that your React version matches >=18.2.0 || ^19.0.0, then check the demo at next-view-transitions.vercel.app against your own page structure.

## FAQ

### What are view transitions in next-view-transitions?

The package exposes the browser View Transitions API to Next.js App Router navigation, so the browser animates between the old and new views on a route change. You opt in by wrapping your layout in the ViewTransitions component and navigating through the package's Link or useTransitionRouter.

### How do I install next-view-transitions?

Install the package with your package manager, for example pnpm install next-view-transitions, then wrap your layout content in the ViewTransitions component. The README places that wrapper outside the html element.

### Does next-view-transitions work with React 19?

The package.json peer dependencies allow react and react-dom at >=18.2.0 || ^19.0.0, so React 19 is inside the declared range. The peer range for Next.js is >=14.0.0.

### Can I use next-view-transitions with Suspense and streaming?

The README's disclaimer states that the library is aimed at basic use cases, and that concurrent rendering, Suspense and streaming still need new primitives in React and Next.js core. That makes these cases a reason to evaluate carefully rather than assume support.

## Sources

- [License: MIT](https://github.com/shuding/next-view-transitions/blob/main/LICENSE)
- [Project website](https://next-view-transitions.vercel.app)
- [README](https://github.com/shuding/next-view-transitions/blob/main/README.md)
- [Releases](https://github.com/shuding/next-view-transitions/releases)
- [shuding/next-view-transitions on GitHub](https://github.com/shuding/next-view-transitions)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shuding-next-view-transitions
