Key re-enters, no key updates

Change the key for new content. Keep it for a cross-fade in place.

Next.js docsnextjs.org
The navigation triggers the transition; the key={slug} change makes React treat the old and new content as an exit/enter pair (activating share) instead of an in-place update.
Crossfade within the same routeRead docs ↗

From vercel-react-view-transitions, patterns.md.

New query, new results

Pick another query.

No key: updateBad
<ViewTransition>
key={query}Good
key={query} enter="slide-up"
<ViewTransition key={query} enter="slide-up" exit="slide-down" default="none">
  <ResultsGrid query={query} />
</ViewTransition>

Tabs: a key refetches

Switch tabs and count the skeletons.

key={tab}Bad

<ViewTransition key={tab}><Suspense>
No key: cross-fadeGood

<ViewTransition><Suspense>
// No key: an update. Old content stays until the new tab is ready, then cross-fades.
<ViewTransition>
  <Suspense fallback={<Skeleton />}>
    <TabPanel tab={activeTab} />
  </Suspense>
</ViewTransition>

Why it matters, pros and cons

Why it matters

Same boundary, new content is an update: a cross-fade in place. A new key unmounts the old boundary and mounts a new one, so exit and enter play.

Pros

  • A key says "these are new results".
  • No key keeps state and skips a Suspense remount.
  • Tabs, panels and carousels cross-fade for free.

Cons

  • A key around Suspense remounts it and refetches.
  • A key resets every piece of state inside.
  • Same-route segments in Next need key + name + share.