/Web APIs


Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.

The ViewTransition interface of the View Transitions API represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether.

This object type is returned by the document.startViewTransition() method. When startViewTransition() is invoked, a sequence of steps is followed as explained in The view transition process. This also explains when the different promises fulfill.

Instance properties

ViewTransition.finished Experimental

A Promise that fulfills once the transition animation is finished, and the new page view is visible and interactive to the user.

ViewTransition.ready Experimental

A Promise that fulfills once the pseudo-element tree is created and the transition animation is about to start.

ViewTransition.updateCallbackDone Experimental

A Promise that fulfills when the promise returned by the document.startViewTransition()'s callback fulfills.

Instance methods

skipTransition() Experimental

Skips the animation part of the view transition, but doesn't skip running the document.startViewTransition() callback that updates the DOM.


In the following example, the ViewTransition.ready promise is used to trigger a custom circular reveal view transition emanating from the position of the user's cursor on click, with animation provided by the Web Animations API.

// Store the last click event
let lastClick;
addEventListener("click", (event) => (lastClick = event));

function spaNavigate(data) {
  // Fallback for browsers that don’t support this API:
  if (!document.startViewTransition) {

  // Get the click position, or fallback to the middle of the screen
  const x = lastClick?.clientX ?? innerWidth / 2;
  const y = lastClick?.clientY ?? innerHeight / 2;
  // Get the distance to the furthest corner
  const endRadius = Math.hypot(
    Math.max(x, innerWidth - x),
    Math.max(y, innerHeight - y)

  // Create a transition:
  const transition = document.startViewTransition(() => {

  // Wait for the pseudo-elements to be created:
  transition.ready.then(() => {
    // Animate the root’s new view
        clipPath: [
          `circle(0 at ${x}px ${y}px)`,
          `circle(${endRadius}px at ${x}px ${y}px)`,
        duration: 500,
        easing: "ease-in",
        // Specify which pseudo-element to animate
        pseudoElement: "::view-transition-new(root)",

This animation also requires the following CSS, to turn off the default CSS animation and stop the old and new view states from blending in any way (the new state "wipes" right over the top of the old state, rather than transitioning in):

::view-transition-image-pair(root) {
  isolation: auto;

::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
  display: block;


Browser compatibility

Desktop Mobile
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on IOS Samsung Internet
ViewTransition 111 111 No No 97 No 111 111 No No No No
finished 111 111 No No 97 No 111 111 No No No No
ready 111 111 No No 97 No 111 111 No No No No
skipTransition 111 111 No No 97 No 111 111 No No No No
updateCallbackDone 111 111 No No 97 No 111 111 No No No No

See also

© 2005–2023 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.