Tying your pages together with ViewTransition
Tying your pages together with ViewTransition
Did you just see that subtle animation of the title when you clicked on the blog post card? No? Then try to spot it here:
This feature is the definition of low hanging (transition) fruit. Let's implement it together.
Still an experimental feature
It is not yet part of production React (or Next.js), so use it with diligence. To start using it, make sure to
- be on Next.js 15.2 or higher
- and to set the experimental flag in your next configuration:
const nextConfig: NextConfig = {
experimental: {
viewTransition: true,
},
};
Wrap relevant elements
We will "rebuild" (it is a very short process) the image and heading positional change in the video above (see it live in action on my service overview page).
- First things first. Import the component at the top of the pages you want to use it on:
import { unstable_ViewTransition as ViewTransition } from "react";
- To get the positional animation all you need to do is to wrap matching elements with the
<ViewTransition>
component both on the page you are coming from as well as the target page. Additionally, give each matching item a unique name
.
name={`serviceTitleImage`}
- If you are heading to a dynamic page make sure that the name is unique by adding a unique element:
name={`serviceTitleImage-${service.mdxMetadata.slug}`}
- This is what it looks like for my Starting page, the services overview page. I wrapped the
<Image>
and <h3>
elements.
import { unstable_ViewTransition as ViewTransition } from "react";
// ...
<div className="relative aspect-4/3 overflow-hidden rounded-2xl">
<ViewTransition name={`serviceTitleImage-${service.mdxMetadata.slug}`} >
<Image
src={service.mdxMetadata.titleImage || "/placeholder.svg"}
alt={service.mdxMetadata.title}
fill
className="object-cover transition-transform duration-500 hover:scale-105"
/>
</ViewTransition>
</div>
// ...
<div className="w-full lg:w-1/2">
<ViewTransition name={`title-${service.mdxMetadata.slug}`}>
<h3 className="mb-4 text-3xl font-bold md:text-4xl">
{service.mdxMetadata.title}
</h3>
</ViewTransition>
</div>
// ...
- And then I wrapped the corresponding elements on the destination page. Note: I also wrapped the overlay
<div>
with the <Image>
to make sure it is also faded during the transition. Cross-fading is the default or fallback animation if an element does not exist on both pages.
import { unstable_ViewTransition as ViewTransition } from "react";
// ...
<ViewTransition name={`serviceTitleImage-${serviceMetadata.slug}`}>
<Image
src={serviceMetadata.titleImage}
alt={serviceMetadata.title}
fill
className="object-cover"
/>
<div className="absolute inset-0 z-10 bg-black/55" />
</ViewTransition>
// ...
<ViewTransition name={`title-${serviceMetadata.slug}`}>
<h1 className="mb-6 max-w-4xl text-5xl font-bold text-white md:text-7xl">
{serviceMetadata.title}
</h1>
<p className="max-w-2xl text-xl text-white/90 md:text-2xl">
{serviceMetadata.shortDescription}
</p>
</ViewTransition>
// ...
That's it. You can now marvel at your smooth transition implementation.
Further reading and reference
Want to see further examples? React has put together a lot of showcases and Next.js created a little demo page whose source code you can check out.
- React Blog: here
- React documentation: here
- Next.js documentation: here