document.startViewTransition()
View Transitions API
Wrap a DOM update in startViewTransition() and the browser screenshots the page before and after, then cross-fades between them. Give matching elements the same view-transition-name and it morphs their position and size too. Libraries used to fake that by measuring an element in both places and animating a clone between them.
The JS
function selectItem(id) {
if (!document.startViewTransition) {
setSelectedId(id);
return;
}
document.startViewTransition(() => {
flushSync(() => setSelectedId(id));
});
}The CSS
/* The same name on a card and on the detail view it opens into
is what the browser morphs between. Set per item, so each card
has its own: card-a, card-b, and so on. */
.gridItem,
.listItem,
.detail {
view-transition-name: var(--vtn, none);
}
/* Both halves of the transition are pseudo-elements, so the timing
is styled, not scripted. */
::view-transition-group(*) {
animation-duration: 0.4s;
animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.25s;
}How it works
Click a card to open its detail view, or switch between Grid and List. Both call document.startViewTransition(callback). The DOM updates synchronously inside the callback, then the browser diffs the old and new frames and animates the difference.
Elements sharing a view-transition-name across both frames get their own mini transition, morphing shape and position instead of cross-fading. That is why the clicked card grows into the detail panel instead of popping in.
The one demo here that needs JavaScript. A same-document transition has to be announced at the moment the DOM changes, and only a script knows when that is. The animation itself is still the browser’s: you style it through the ::view-transition-old() and ::view-transition-new() pseudo-elements. Between pages you don’t need a script at all, since @view-transition { navigation: auto } hands the whole thing over.
turns, wins and reset, all CSS
trigonometry, in CSS
switch guests on