Element View Transition API #5670
ViewableGravy
started this conversation in
RFCs
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
I wanted to create a document/discussion for how tanstack router might implement an API to support element level view transitions. The motivation behind this is the recent implementation and addition of this behind a flag in chrome 140, and the rationale that supporting element transitions in a routing library seems like an extremely reasonable place to do so, since we are often only swapping out portions of the application, and not necessarily the entire page.
This lends well to element transitions because we can simply animate the lowest non-replacing router matches children, allowing sections of a page to be animated while keeping the layout of the page static if it is not being replaced.
This proposal defines a rough, opt-in API surface for route-level transitions that integrates naturally with TanStack’s existing patterns, while enabling full use of Chrome’s new element-based transitions.
Note: This discussion is mostly relating to API design and not implementation details at this stage.
Disclaimer: AI was used in improving the writing of this proposal
View Transitions API.
Motivation
View transitions currently solve animation between pages, but at a cost. Currently, a document view transition overlays the entire document with the transition layer, which is then animated. this causes the entire page to be blocked from interaction while it is animating.
The element level transition API solves this by providing the animation at an element level (or in the router case, a match/outlet level). This allows us to animate sub-trees of the dom, while keeping layout related content such as headers, footers, etc, that exist across routes to remain interactive and opt out of animations.
For route-based applications, the most logical boundary to animate is the outlet of a route that remains mounted during navigation.
Proposed Additions
transitionComponent Route Option
transitionComponentaccepts either:If present, this component should wrap the child outlet of the route. This defines the transition boundary for its child routes.
💡This differs from pendingComponent and errorComponent, which wrap the route itself. In this case, the route provides a transition boundary for its children, not for itself. This is intentional — when a route is unmounted, it cannot animate its own exit, as the incoming route will (likely) not share a transition name/id, and would potentially define it's own transition/component/etc. Therefore, the logical approach is for a route to offer a transition context to its children rather than expect one.
From a type-level perspective, I would expect this to only exist on non-leaf routes, as it applies to it's children, and lead nodes do not have children
I do recognise that this could be confusing for a user, as it behaves differently to other functionality, but it seems reasonable in this case
Route.useRegisterTransition Hook, Component or HOC
Since transitionComponent cannot (should not) receive props other than children (consistent with other route components), an approach to creating a transitionComponent would be required. There are a few options that come to mind
Hook Approach with children prop
This approach is a hybrid of prop injection (children prop is easy to type manually) while relying on a hook to provide an inferred
ref callback.
Hook Approach with Outlet (or TransitionOutlet)
This approach doesn't require any types being manually defined, and does not inject props, but introduces two new concepts for registering an outlet which seems heavy handed (although better than injecting props)
HOC Approach
This approach would infer the types for ref and children (as well as creating a forward ref in older react versions) by using a HOC.
Suggestion
Personally I am leaning to
createTransitionComponentas it provides the least new features specifically for view transitions, while inferring all types. It also allows us to avoid manually creating a ForwardRef if the react version does not support it. The other options feel "clunky" in one way or another in my opinionGlobal Default Option: mode
Extend the defaultViewTransition configuration in createRouter with a mode field:
"element": Use the new element transition model. If a route doesn’t define transitionComponent, a
<div>will be used automatically."document": Maintain existing document-level transitions (current behavior).
This provides a clean global opt-in without changing existing projects.
Behavior Summary
defaultViewTransition.mode. Routes may add transitionComponent individually if desired.<div>automatically wraps the outlet.Route.useRegisterTransition()returns a ref callback for the transition element.document.startViewTransitionis unsupported.view-transition-*CSS for animations.Example Usage
In this example:
Additional Notes
Async loaders:
No special handling needed — transitions start once routes are ready to render, consistent with current behavior.
History / scroll restoration:
Unaffected. Standard router behavior continues to apply.
Nested transitions:
If multiple transition elements exist in nested routes, the browser’s View Transition API should handle coordination automatically (needs confirmation through testing).
Non-supporting browsers:
Detection and fallback to no-op at runtime.
Summary
This proposal introduces:
Beta Was this translation helpful? Give feedback.
All reactions