How to Use the View Transitions API in JavaScript
The View Transitions API provides a native mechanism for creating seamless visual transitions between different DOM states or pages. This article explains what the View Transitions API is, how it simplifies animated UI states without complex third-party libraries, and how JavaScript works alongside CSS pseudo-elements to capture snapshots, update the DOM, and coordinate smooth animations.
What Is the View Transitions API?
Traditionally, animating changes between two different states in a web application required complex JavaScript libraries, absolute positioning hacks, and manual calculation of element coordinates. The View Transitions API solves this by providing a browser-native way to animate transitions.
It takes a snapshot of the current DOM state (“old” view), pauses rendering while JavaScript updates the DOM, takes a snapshot of the updated state (“new” view), and then automatically cross-fades or animates between the two using CSS animations.
How JavaScript Coordinates the Transition
JavaScript coordinates the transition lifecycle using a single core
method: document.startViewTransition().
The Basic Implementation
To initiate a transition, you pass a callback function to
document.startViewTransition() that updates the DOM:
function updateContent() {
// Check for browser support
if (!document.startViewTransition) {
updateDOM();
return;
}
// Coordinate the transition
const transition = document.startViewTransition(() => {
updateDOM();
});
}
function updateDOM() {
const container = document.querySelector("#content");
container.textContent = "New content loaded dynamically.";
}The Lifecycle Steps
When document.startViewTransition() is called, the
browser executes the following sequence:
- Capture Old State: The browser captures a screenshot of the elements marked for transition.
- DOM Update Callback: The callback function passed
to
startViewTransitionruns. If the callback returns a Promise, the browser waits for the Promise to resolve (allowing for asynchronous data fetching or template rendering). - Capture New State: The browser captures a screenshot of the new DOM state.
- Construct Pseudo-Element Tree: The browser creates a pseudo-element tree representing the old and new states.
- Animate: The browser animates the transition from the old screenshot to the new screenshot using standard CSS animations (a cross-fade by default).
- Clean Up: Once the animation completes, the pseudo-elements are removed from the DOM.
Handling Asynchronous DOM Updates
If your DOM update relies on asynchronous operations, such as fetching data from an API, return a Promise inside the callback:
async function navigateToPage(url) {
if (!document.startViewTransition) {
await fetchAndRender(url);
return;
}
const transition = document.startViewTransition(async () => {
await fetchAndRender(url);
});
// Optional: Wait for the transition animation to finish
await transition.finished;
console.log("Transition animation has completed.");
}The startViewTransition() method returns a
ViewTransition object with several Promises: *
transition.updateCallbackDone: Resolves when the DOM update
function finishes. * transition.ready: Resolves when the
pseudo-element tree is created and animations are about to run. *
transition.finished: Resolves when all animations have
completed and the UI is fully interactive.
Customizing Animations with CSS
While JavaScript coordinates the timing and state changes, CSS controls the visual presentation.
By default, the entire page (:root) undergoes a
cross-fade transition. You can assign unique transitions to specific
elements by giving them a view-transition-name:
.card-header {
view-transition-name: card-header;
}The browser automatically handles the size, position, and opacity
changes for any element with an assigned
view-transition-name, interpolating between the old and new
positions seamlessly.
You can customize the animation using the generated pseudo-element tree:
::view-transition-old(card-header) {
animation: slide-out 0.3s ease-out;
}
::view-transition-new(card-header) {
animation: slide-in 0.3s ease-in;
}
@keyframes slide-out {
to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in {
from { transform: translateX(100%); opacity: 0; }
}Benefits of the View Transitions API
- Performance: Animations run on the compositor thread using captured screenshots, reducing layout recalculations and jank.
- Progressive Enhancement: If a browser does not support the API, the callback simply runs immediately, ensuring the DOM updates without breaking functionality.
- Simplified Code: Replaces heavy JavaScript layout-tracking logic with standard CSS animations.