Skip to content

Last updated: First published:

View Transition JavaScript API

Browser-native cross-document view transitions can be created entirely with CSS, without the need for JavaScript. However, JavaScript becomes essential for advanced functionality, such as:

  • Triggering same-page view transitions with startViewTransition(),
  • Dynamically modifying CSS properties like view-transition-name,
  • Defining view transition types,
  • Executing code at the start or end of a transition.

Same-Document View Transitions

Same document view transitions are amazing! You assign view transition names to the HTML elements you want to animate during the transition. The transition spans from the current DOM state to a future version, which is generated by calling and awaiting an update function.

startViewTransition()

Typically, you start a same-document view transition with an update callback that transforms the current DOM to the future state. The View Transition API takes care of creating and running animations that smoothly transform the old state into the new one.

if (window.matchMedia('(prefers-reduced-motion: reduce)') || !document.startViewTransition) {
updateCallback()
} else {
document.startViewTransition(updateCallback);
}

For users who prefer reduced motion or when the browser doesn’t support the View Transition API, the code above directly executes the update function without calling startViewTransition().

The update callback can either be a synchronous or asynchronous function. If it’s asynchronous, the View Transition API will wait for it to settle. However, you should aim to spend only little time inside the callback. For one thing, the browser freezes the renderer while the update callback executes. And browsers may impose time limits. For Chrome this seem to be 4 seconds before it loses its temper. If you need an expensive preparation for the transition, like loading and parsing a new DOM from file, you better do that before you call startViewTransition(). The update callback is optional, so you can even transition to the same version of the DOM by omitting the update function, which might make sense with custom animations.

You can also pass an options object to startViewTransition() to define view transition types that should be active during the transition.

document.startViewTransition({
types: ["boom", "backward"],
update: changeTheDOM,
});

Here is the full signature for startViewTransition

type UpdateCallback = undefined | (() => void | Promise<void>);
type StartViewTransitionOptions = {
types?: string[] | Set<string>;
update?: UpdateCallback;
};
interface Document {
startViewTransition(
param?: StartViewTransitionOptions | UpdateCallback
): ViewTransition;
}

ViewTransition Object

The startViewTransition() function returns an object that includes promises, the current transition types, and a function to skip the animations.

interface ViewTransition {
readonly updateCallbackDone: Promise<undefined>;
readonly ready: Promise<undefined>;
readonly finished: Promise<undefined>;
readonly types: Set<string>;
skipTransition(): void;
}

Promises

The promises allow you to hook into the different stages of the view transition process.

  • The updateCallbackDone promise resolves once the update callback has finished. You can use this to (synchronously) make last-minute changes before the new images are created. If the promise rejects, view transition processing ends, and the finished promise also rejects.

  • The ready promise settles once the pseudo-elements have been inserted into the DOM. Inserting the pseudo-elements triggers their animations. For example, you can use this promise to add your own JavaScript animations using the Web Animation API. If there are errors, like duplicate view transition names, the ready promise will reject.

  • Lastly, the finished promise settles once the animations are complete and the pseudo-elements have been removed. It resolves with the same outcome as updateCallbackDone.

When using the promises, your call to startViewTransition() might look something like this:

if (document.startViewTransition && window.matchMedia('(prefers-reduced-motion: no-preference)')) {
const viewTransition = document.startViewTransition({update: updateCallback, types: ...});
viewTransition.updateCallbackDone.catch(err => ... error handling ...);
viewTransition.ready.catch(err => ... error handling ...);
viewTransition.ready.then(() => ... trigger parallel animation ...);
viewTransition.finished.finally(() => ... clean up ...)
} else {
updateCallback();
}

skipTransition()

Calling skipTransition() stops the current view transition animations or prevents their start if the ready promise hasn’t settled yet. If called during the update callback, it doesn’t affect the update itself, nor does it impact the processing or the outcome of the updateCallbackDone promise.

Types

You can dynamically add or remove view transition types during the view transition by modifying the types object. Such changes will directly affect CSS rules that use the :active-view-transition-type pseudo-class.

Canceling and Chaining

Calling startViewTransition() while another view transition is active will interrupt the current view transition, fast forward to the end state of the animations, and start the new view transition from there.

Currently, browser behavior differs regarding the effects that occur when startViewTransition is called before updateCallbackDone resolves. You should better avoid this scenario. You can either chain the update callback functions and pass the chained callback to a single call of startViewTransition(), or chain multiple calls to startViewTransition() by awaiting the finished promise before starting the next view transition.

Cross-Document View Transitions

Cross-document view transitions work similarly to same-document ones but are triggered by navigation. In particular you can get access to the view transition object in event listeners for the new pageswap and pagereveal events.

Pageswap and Pagereveal Events

Two key events enable JavaScript interaction: pageswap, dispatched just before leaving the old page, and pagereveal, dispatched before the new page renders.

ViewTransition Object

Both events include a viewTransition property, which holds a ViewTransition object if the transition is part of a cross-document view transition. The object has the same structure as for same-document view transitions.

For pageswap, if viewTransition is defined, its promises will never settle because the page is unloaded before it is “updated”. For pagereveal, if viewTransition is defined, its updateCallbackDone promise is immediately settled.

The events allow you to manipulate the DOM or CSS properties right before snapshots are taken or the new page’s live images are captured. In particular, they allow for setting view transition types for the current view transition.

In a pageswap listener, you can define view transition types by adding them to event.viewTransition.types, which are then only applied to the old page. The types can be used to control via CSS what view transition names are defined on the old page. You can also directly modify view transition names in the listener as snapshots for the ::view-transition-old pseudo elements are taken after this event is dispatched.

Similarly, pagereveal listeners allow you to tweak view transition names and types for the new page. Again, live images for the ::view-transition-new pseudo-elements are being captured after the event.

Activation Object

The pageswap event also provides a NavigationActivation object via its activation property, offering details about the current page (from) and next page (entry). While the pagereveal event does not include this property, in browsers supporting the Navigation API, you can use navigation.activation to access information about the previous page (from) and current page (entry).