Handle rejected ViewTransition ready/finished promises
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Which project does this relate to?
TanStack Router (@tanstack/react-router@1.170.18, with @tanstack/router-core@1.171.15 transitively installed)
Describe the bug
When a navigation enables viewTransition, RouterCore.startViewTransition calls document.startViewTransition(...) but discards the returned ViewTransition object.
Browsers may reject ViewTransition.ready or ViewTransition.finished for normal lifecycle conditions, including a document becoming hidden or a transition being superseded. Because the promises have no rejection handlers, these can become unhandled promise rejections even though the router commits the new location successfully.
One Chromium case is:
InvalidStateError: Transition was aborted because of invalid state
Complete minimal reproduction
Repository: https://github.com/David-0x221Eight/tanstack-router-view-transition-repro
Versions:
@tanstack/react-router@1.170.18@tanstack/router-core@1.171.15(transitive dependency)react@19.2.8vite@8.1.5
Steps in Chrome:
- Run
npm installandnpm run dev. - Open the local page and the DevTools console.
- Click Arm reproduction.
- Switch to another browser tab, wait briefly, and return.
The app uses the real browser API. It never replaces, wraps, or mocks document.startViewTransition. It listens for the real visibilitychange event, then calls:
router.navigate({
to: "/next",
viewTransition: true,
});
while the document is genuinely hidden. Its unhandledrejection observer only displays the rejection and does not call preventDefault().
Observed result in Chrome:
/nextcommits and the destination content renders;- the page receives an unhandled rejection;
- Chrome reports
InvalidStateError: Transition was aborted because of invalid statein the DevTools console.
Expected behavior
Router should consume rejections from the lifecycle promises it creates. Expected transition aborts should not become global errors; unexpected failures should remain observable.
A possible shape is:
const transition = document.startViewTransition(startViewTransitionParams)
void transition.ready.catch(handleViewTransitionRejection)
void transition.finished.catch(handleViewTransitionRejection)
For example, the handler can ignore AbortError and the Chromium InvalidStateError above, while forwarding other errors to globalThis.reportError (or console.error when unavailable).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at RouterCore.startViewTransition and run the linked minimal reproduction with npm install and npm run dev, then reproduce the hidden-document navigation in Chrome. Ensure rejections from the created lifecycle promises no longer become unhandled for expected aborts while unexpected failures remain observable, and verify that /next still commits.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100