Morph the same thing by name
Give the thumbnail and the detail one name; the browser morphs them.
Next.js docsnextjs.org
The name prop creates identity. React finds elements with the same name on the old and new pages, then animates between their size and position automatically.
From vercel-react-view-transitions, SKILL.md.
Thumbnail to detail
Open a photo, then go back.
No nameBad
<Image src={photo.thumb} />name={`photo-${id}`}Good
name={`photo-${id}`} share="morph"// Grid
<ViewTransition name={`photo-${photo.id}`} share="morph" default="none">
<Image src={photo.thumb} />
</ViewTransition>
// Detail: same name
<ViewTransition name={`photo-${photo.id}`} share="morph">
<Image src={photo.full} />
</ViewTransition>
::view-transition-group(.morph) { animation-duration: 400ms; }
::view-transition-image-pair(.morph) { animation-name: via-blur; }
@keyframes via-blur { 30% { filter: blur(3px); } }
Text morphs without ghosting
Open the note and watch the title.
share="morph"Bad
share="morph"share="text-morph"Good
share="text-morph"<ViewTransition name={`title-${post.id}`} share="text-morph" />
::view-transition-group(.text-morph) { animation-duration: 400ms; }
::view-transition-old(.text-morph) { display: none; }
::view-transition-new(.text-morph) {
animation: none;
object-fit: none;
object-position: left top;
}
Why it matters, pros and cons
Why it matters
One name on both ends says "this is the same object". The eye follows one photo moving instead of matching two that swapped.
Pros
- No scanning to confirm what you opened.
- The browser does the position math.
- Nests inside a keyed list item boundary.
Cons
- Both ends must render in the same commit; a Suspense fallback breaks it.
- Snapshots are images: big text needs
text-morph. - Named elements ignore clicks mid-transition.