all writing

View Transitions: More Options, Less Movement

Element-scoped View Transitions open up useful possibilities. Why I still start with a simple fade and keep movement deliberately restrained.

The transitions on this website say quite a lot about how I think about animation. We tried more prominent effects, then returned to a quiet fade out and fade in. The more interesting technique did not automatically produce the better design.

I have been thinking about that again as the View Transition API gains new capabilities. Transitions limited to part of an interface are particularly interesting to me. A sorted list can change while I continue working beside it. I can see more useful applications for that than for another animation taking over the whole screen.

What changed this year

Chrome 147 introduced element-scoped View Transitions. Calling Element.startViewTransition() limits a transition to a DOM subtree, enabling concurrent and nested transitions. The announcement published on March 27, 2026 explains the change and includes demonstrations. This is a specific Chrome release, rather than a promise of support across every browser. Chrome: Element-scoped View Transitions

What appeals to me is that boundary. When a card changes, my navigation should not need to join the animation. When I filter a list, I want to understand which entries remain. The effect should help explain that change.

The document-scoped version uses document.startViewTransition(). It captures states around a DOM update within the same document. Navigation between separate documents is a different use case with its own setup. MDN: Document.startViewTransition

Make the update work first

For a small exploration, I would start with a function that updates an existing card. This JavaScript is deliberately an isolated example for an already rendered interface. It is not a recipe for mixing direct DOM manipulation with a React router's state model.

Example
javascript
function updateCard(card, update) {  const reduced = matchMedia(    '(prefers-reduced-motion: reduce)'  ).matches;
if (reduced || typeof card.startViewTransition !== 'function') { update(); return; }
card.startViewTransition(update);}
const card = document.querySelector('[data-status]');if (card) { updateCard(card, () => { card.textContent = 'Saved'; });}

The important part is the direct update() call when the effect is unavailable or unwanted. The card still works. Animation must never become a requirement for a change to appear.

The prefers-reduced-motion media query lets us check a person's reduced-motion preference. I treat that preference as a design requirement and skip the transition entirely in this example. MDN: prefers-reduced-motion

The order I prefer to work in

I start with an interface that has no animation. Does its spacing stay stable? Is my location clear after navigating? Does an image push the content around when it loads? A fade does not solve those problems. Sometimes the fade makes them easier to notice.

Only then do I decide whether a transition helps. A short fade is often enough for a page change. In a gallery, maintaining a visible connection between a thumbnail and its larger image can be useful. In a dense working interface, I would use movement even more sparingly.

Then I try quick repeated clicks, long content and the back button. An animation that looks good on a carefully prepared first click is not yet a reliable interaction. I want it to behave predictably when someone is simply trying to get somewhere.

The new APIs make local transitions more interesting. My design rule remains simple: I want to make changes easier to understand. Once the animation draws more attention than the change itself, I start taking things out again.