feat(ui): migrate route transitions to React ViewTransition on Next 16.3 - #250
Merged
Conversation
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)
This was referenced Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 inconfig-schema/config-shared; zerostartViewTransitioninnext/dist/client). The::view-transition-*(root)cross-fade inglobals.csswas 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 (noreact@canaryinstall), and every<Link>navigation already runs insideReact.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 removedcomponents/page-transition.tsx(new):<ViewTransition enter="page-fade" exit="page-fade" default="none">boundary. Includes a runtime passthrough guard because vitest resolves stablereact@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).page.tsxwrapped (admin/studio excluded;sobre-miis a barepermanentRedirectand 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/reactships it natively this file gets deleted, not edited.Tests
tsc --noEmit: exit 0 (this is the check chore(deps): bump next from 16.2.11 to 16.3.0 in the next group across 1 directory #249 fails)biome check: exit 0vitest run: 562/562 passed (71 files, local box)next buildper standing rule — the Vercel preview build is the build validation. The animation itself is only exercised by Next's bundled canary at runtime; verify the cross-fade on the preview deploy.Reviewed (reliability lens, 1 sweep)
No BLOCKER/CRITICAL. 3 WARNING: (1) dead
PageTransitionwrapper on thesobre-miredirect — fixed, page excluded; (2)@types/reactforward-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)
<Link transitionTypes={['nav-forward'|'nav-back']}>+ slide CSS)types/view-transition.d.tswhen@types/reactshipsViewTransition