Skip to content

feat(ui): migrate route transitions to React ViewTransition on Next 16.3 - #250

Merged
JNZader merged 1 commit into
mainfrom
feat/next-16-3-view-transitions
Aug 17, 2026
Merged

feat(ui): migrate route transitions to React ViewTransition on Next 16.3#250
JNZader merged 1 commit into
mainfrom
feat/next-16-3-view-transitions

Conversation

@JNZader

@JNZader JNZader commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Next 16.3 removed experimental.viewTransition (vercel/next.js#96098) — and the reason matters: the flag was already inert. Nothing in the 16.2.x runtime read it (verified locally: the string appears only in config-schema/config-shared; zero startViewTransition in next/dist/client). The ::view-transition-*(root) cross-fade in globals.css was dead code. On top of that, the flag's removal is the sole reason the Next 16.3 bump (#249) fails type-checking — so this PR supersedes it.

The replacement is the official 16.3 model: <ViewTransition> ships in Next's bundled React canary (no react@canary install), and every <Link> navigation already runs inside React.startTransition, so boundaries activate on route changes with zero config.

What changed

  • next: ^16.2.11^16.3.0 (resolves 16.3.1)
  • next.config.ts: inert flag removed
  • components/page-transition.tsx (new): <ViewTransition enter="page-fade" exit="page-fade" default="none"> boundary. Includes a runtime passthrough guard because vitest resolves stable react@19.2.x, which lacks the export — without it, page-rendering tests crash on "Element type is invalid". In Next (dev/prod) the real boundary is used; verified the export exists in both bundled builds (react.development.js:878, react.react-server.development.js:596).
  • 12 public page.tsx wrapped (admin/studio excluded; sobre-mi is a bare permanentRedirect and renders nothing — excluded with a comment instead of a dishonest wrapper).
  • globals.css: (root) selectors → class-based (.page-fade), preserving the 160ms-out / 220ms-in timings; added ::view-transition { pointer-events: none }; reduced-motion now zeroes durations on all pseudo-elements.
  • types/view-transition.d.ts (new): module augmentation — the canary API is not in @types/react@19.2.x. Marked FORWARD-RISK: when @types/react ships it natively this file gets deleted, not edited.

Tests

Reviewed (reliability lens, 1 sweep)

No BLOCKER/CRITICAL. 3 WARNING: (1) dead PageTransition wrapper on the sobre-mi redirect — fixed, page excluded; (2) @types/react forward-conflict in the augmentation — fixed with a delete-me comment; (3) the silent runtime guard — accepted, it exists for the stable-react test runner and the export is verified present in both Next 16.3.1 bundles.

Follow-ups (NOT in this PR)

  • Directional navigation (<Link transitionTypes={['nav-forward'|'nav-back']}> + slide CSS)
  • Shared-element morphs (project thumbnail → project detail hero) — the highest-value pattern for a portfolio per the official guide
  • Delete types/view-transition.d.ts when @types/react ships ViewTransition

experimental.viewTransition was removed in Next 16.3 (vercel/next.js#96098)
because the flag was already inert — nothing in the runtime read it, so the
::view-transition-*(root) cross-fade CSS was dead code. The App Router bundles
React canary with <ViewTransition>, and Link navigations already run inside
React.startTransition, so transitions now work with zero config.

- Bump next ^16.2.11 -> ^16.3.0 (resolves 16.3.1)
- Remove the inert experimental.viewTransition flag from next.config.ts
- Add components/page-transition.tsx: <ViewTransition enter/exit="page-fade"
  default="none"> boundary with a runtime passthrough guard for the test
  runner (vitest resolves stable react@19.2.x, which lacks the export)
- Wrap the 12 public page.tsx entry points (admin/studio excluded; sobre-mi
  is a permanentRedirect and renders nothing)
- Migrate globals.css from ::view-transition-*(root) to class-based
  ::view-transition-*(.page-fade), preserving the 160ms/220ms timings; add
  ::view-transition { pointer-events: none }; reduced-motion zeroes durations
  on all pseudo-elements
- Add types/view-transition.d.ts module augmentation (canary API not yet in
  @types/react@19.2.x; marked FORWARD-RISK to delete when it ships natively)
@JNZader
JNZader merged commit bba1222 into main Aug 17, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant