Skip to content

Conversation

@ha1fstack
Copy link
Contributor

@ha1fstack ha1fstack commented Nov 13, 2025

Added the following router events so we could access view transition events and ViewTransition instance.

export type ViewTransitionEventInfo = {
  transition: ViewTransition
}

export interface RouterEvents {
  onViewTransitionStart: {
    type: 'onViewTransitionStart'
  } & ViewTransitionEventInfo &
    NavigationEventInfo
  onViewTransitionReady: {
    type: 'onViewTransitionReady'
  } & ViewTransitionEventInfo &
    NavigationEventInfo
  onViewTransitionUpdateCallbackDone: {
    type: 'onViewTransitionUpdateCallbackDone'
  } & ViewTransitionEventInfo &
    NavigationEventInfo
  onViewTransitionFinish: {
    type: 'onViewTransitionFinish'
  } & ViewTransitionEventInfo &
    NavigationEventInfo
  ...

Summary by CodeRabbit

  • New Features

    • Added four view-transition lifecycle events (onViewTransitionStart, onViewTransitionReady, onViewTransitionUpdateCallbackDone, onViewTransitionFinish) that include the transition object and navigation context.
    • Transition events now receive a unified location-change context reused across navigation and load flows.
  • Documentation

    • Event payloads updated: added hashChanged flag and expanded onRendered payload (pathChanged, hrefChanged, hashChanged); docs updated for new view-transition events.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 13, 2025

Walkthrough

Adds ViewTransition types and a LocationChangeInfo type to router core; threads a single computed location-change context through navigation and load flows; updates startViewTransition to accept LocationChangeInfo and emit four view-transition lifecycle events (start, ready, update-callback-done, finish) carrying both transition and location-change data; documents a new hashChanged flag on several RouterEvents payloads.

Changes

Cohort / File(s) Summary
Router core & types
packages/router-core/src/router.ts
Added public ViewTransitionEventInfo and exported LocationChangeInfo. Extended RouterEvents with onViewTransitionStart, onViewTransitionReady, onViewTransitionUpdateCallbackDone, and onViewTransitionFinish. Updated startViewTransition signature to accept (locationChangeInfo, fn) and emit the four lifecycle events, and replaced inline getLocationChangeInfo calls by computing a single locationChangeInfo per navigation/load flow.
Public exports
packages/router-core/src/index.ts
Re-exported LocationChangeInfo from router core.
Docs: RouterEvents type
docs/router/framework/react/api/router/RouterEventsType.md
Added hashChanged: boolean to multiple RouterEvents payloads and documented the four new view-transition events and their payload shapes (each includes transition: ViewTransition, optional fromLocation/toLocation, and flags pathChanged, hrefChanged, hashChanged).

Sequence Diagram(s)

sequenceDiagram
    participant Router as Router
    participant DOM as Document API
    participant Listener as Event Listener

    Router->>Router: startViewTransition(locationChangeInfo, fn)
    Router->>DOM: document.startViewTransition(fn)
    DOM-->>Router: transition

    rect `#E8F0FF`
      Router->>Listener: emit onViewTransitionStart (transition + locationChangeInfo)
    end

    rect `#FFF4E6`
      DOM->>Router: transition.ready
      Router->>Listener: emit onViewTransitionReady (transition + locationChangeInfo)
    end

    rect `#F6FFF2`
      DOM->>Router: transition.updateCallbackDone
      Router->>Listener: emit onViewTransitionUpdateCallbackDone (transition + locationChangeInfo)
    end

    rect `#F0FFF7`
      DOM->>Router: transition.finished
      Router->>Listener: emit onViewTransitionFinish (transition + locationChangeInfo)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Reviewers should focus on:
    • All updated call sites where getLocationChangeInfo was consolidated to ensure correct context is computed and passed.
    • Promise handlers for ready, updateCallbackDone, and finished to verify correct emission ordering and closure capture of locationChangeInfo.
    • Type surface: RouterEvents additions and the exported LocationChangeInfo alignment with docs.

Possibly related PRs

Suggested reviewers

  • schiller-manuel
  • SeanCassiere

Poem

I’m a rabbit in the router tree,
I stash a LocationChange key,
Start, ready, update, then done,
Four little hops — a transition run,
I nibble hashes, paths, and fun. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add view transition events' directly and concisely summarizes the main change: adding new view transition-related events to the router's event system.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f034cd9 and e482a3a.

📒 Files selected for processing (2)
  • packages/router-core/src/index.ts (1 hunks)
  • packages/router-core/src/router.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/index.ts
  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/index.ts
  • packages/router-core/src/router.ts
🧠 Learnings (6)
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/index.ts
  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/index.ts
  • packages/router-core/src/router.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-devtools,*-router-devtools}/** : Keep router devtools packages in packages/router-devtools/ and packages/*-router-devtools/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/** : Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Applied to files:

  • packages/router-core/src/router.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (5)
packages/router-core/src/index.ts (1)

211-211: LGTM!

The LocationChangeInfo export is correctly positioned and necessary for exposing the new view transition API types to consumers.

packages/router-core/src/router.ts (4)

547-550: LGTM!

The ViewTransitionEventInfo type correctly wraps the ViewTransition instance. The @ts-ignore comment appropriately handles TypeScript versions prior to 5.6.


571-586: LGTM!

The four new view transition lifecycle events are properly typed and follow the existing event pattern by combining ViewTransitionEventInfo and NavigationEventInfo.


790-796: LGTM!

The LocationChangeInfo interface properly captures navigation context with location references and change flags. The structure aligns well with the existing NavigationEventInfo type.


2114-2129: LGTM!

Computing locationChangeInfo once and reusing it across event emissions is efficient and ensures consistency. The updated event payloads now provide comprehensive navigation context.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Nov 13, 2025

View your CI Pipeline Execution ↗ for commit 6b9283b

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 1m 8s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-13 17:25:09 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 13, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5861

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5861

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5861

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5861

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5861

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5861

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5861

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5861

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5861

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5861

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5861

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5861

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5861

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5861

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5861

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5861

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5861

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5861

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5861

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5861

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5861

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5861

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5861

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5861

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5861

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5861

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5861

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5861

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5861

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5861

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5861

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5861

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5861

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5861

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5861

commit: 6b9283b

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfb4f9a and 91c4394.

📒 Files selected for processing (1)
  • packages/router-core/src/router.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (2)
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test

@github-actions github-actions bot added the documentation Everything documentation related label Nov 13, 2025
@ha1fstack ha1fstack force-pushed the feat/view-transition-events branch from c6c270d to 813e9a9 Compare November 13, 2025 16:55
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/router-core/src/router.ts (1)

2312-2338: Handle failed view-transition promises to avoid unhandled rejections.

The .then(...) calls on transition.ready, transition.updateCallbackDone, and transition.finished lack rejection handlers. These promises reject in legitimate scenarios (e.g., duplicate view-transition-name values or rejected update callbacks), causing "Unhandled promise rejection" console errors even though the router gracefully falls back to non-animated updates.

Apply this diff to add rejection handlers:

-      transition.ready.then(() => {
+      transition.ready.then(
+        () => {
           this.emit({
             type: 'onViewTransitionReady',
             transition,
             ...locationChangeInfo,
           })
-      })
-      transition.updateCallbackDone.then(() => {
+        },
+        () => {},
+      )
+      transition.updateCallbackDone.then(
+        () => {
           this.emit({
             type: 'onViewTransitionUpdateCallbackDone',
             transition,
             ...locationChangeInfo,
           })
-      })
-      transition.finished.then(() => {
+        },
+        () => {},
+      )
+      transition.finished.then(
+        () => {
           this.emit({
             type: 'onViewTransitionFinish',
             transition,
             ...locationChangeInfo,
           })
-      })
+        },
+        () => {},
+      )
🧹 Nitpick comments (1)
packages/router-core/src/router.ts (1)

2286-2296: Consider reusing the locationChangeInfo parameter.

Lines 2292-2295 recompute getLocationChangeInfo, but this function already received a pre-computed locationChangeInfo parameter. Reusing the parameter eliminates redundant computation.

Apply this diff:

       if (
         typeof shouldViewTransition === 'object' &&
         this.isViewTransitionTypesSupported
       ) {
-        const next = this.latestLocation
-        const prevLocation = this.state.resolvedLocation
-
         const resolvedViewTransitionTypes =
           typeof shouldViewTransition.types === 'function'
-            ? shouldViewTransition.types(
-                getLocationChangeInfo({
-                  resolvedLocation: prevLocation,
-                  location: next,
-                }),
-              )
+            ? shouldViewTransition.types(locationChangeInfo)
             : shouldViewTransition.types
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6c270d and 813e9a9.

📒 Files selected for processing (2)
  • docs/router/framework/react/api/router/RouterEventsType.md (4 hunks)
  • packages/router-core/src/router.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Use internal docs links relative to the docs/ folder (e.g., ./guide/data-loading)

Files:

  • docs/router/framework/react/api/router/RouterEventsType.md
docs/{router,start}/**

📄 CodeRabbit inference engine (AGENTS.md)

Place router docs under docs/router/ and start framework docs under docs/start/

Files:

  • docs/router/framework/react/api/router/RouterEventsType.md
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (3)
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • docs/router/framework/react/api/router/RouterEventsType.md
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (9)
packages/router-core/src/router.ts (5)

547-550: LGTM! Clean type definition for view transition events.

The ViewTransitionEventInfo type properly encapsulates the ViewTransition instance, and the @ts-ignore comment is appropriate given that ViewTransition support requires TypeScript 5.6+.


571-587: LGTM! Well-structured view transition events.

The four new events properly mirror the View Transition API lifecycle and correctly combine ViewTransitionEventInfo and NavigationEventInfo. The type structure ensures consumers receive both the transition instance and location-change context.


851-851: Good type alias for reusability.

The LocationChangeInfo type alias provides a clean, reusable type for location-change data.


2113-2128: Excellent optimization to compute location-change info once.

Computing locationChangeInfo upfront and reusing it across multiple event emissions eliminates redundant calculations and ensures consistency.


2260-2263: Function signature properly updated.

The startViewTransition method now correctly accepts locationChangeInfo as a parameter, enabling the emission of view transition events with location-change context.

docs/router/framework/react/api/router/RouterEventsType.md (4)

16-61: Documentation accurately reflects hashChanged additions.

The hashChanged property is correctly documented for all navigation lifecycle events, matching the code implementation.


62-97: Comprehensive documentation of view transition events.

All four view transition lifecycle events are clearly documented with complete property lists that accurately match the TypeScript definitions.


107-107: Type union properly updated.

The event type union now includes all four new view transition events.


131-142: Clear documentation of new properties.

The hashChanged and transition properties are well-documented with appropriate type information and helpful context. The MDN link for ViewTransition is a valuable reference.

@birkskyum
Copy link
Member

birkskyum commented Nov 14, 2025

@ha1fstack , I've made two e2e suites (one for react-router, one for solid-router) in here, that are ready to add tests after rebasing this PR.

If you add some cases/routes in the app.spec.ts to check the events fire as expected, then we can move this forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants