View Transitions for Color UIs: Instant Theme Swaps Without Flicker
The View Transitions API ships native cross-fade and morph animations for any DOM change - including theme swaps. Here is how to wire it up for color tooling.
Theme toggles have a long-standing problem: the browser repaints all at once, and any image, gradient, or shadow flickers visibly during the swap. The View Transitions API fixes this in a single line of JavaScript.
The one-liner
function toggleTheme() {
if (!document.startViewTransition) {
document.documentElement.classList.toggle('dark');
return;
}
document.startViewTransition(() => {
document.documentElement.classList.toggle('dark');
});
}
That is the entire upgrade. The browser snapshots the page before your callback runs, applies the change, snapshots after, and cross-fades between the two. No CSS transitions on every token.
Customising the animation
By default, you get a 250ms cross-fade. Replace it with anything CSS can express:
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
}
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) { animation: none; }
}
Notice the reduced-motion guard. Always include it - users with vestibular disorders should never be forced through a transition.
Circular reveal from the toggle button
Pair the API with clip-path for the "ink ripple" effect popularized by Material 3:
const x = event.clientX, y = event.clientY;
const r = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
const t = document.startViewTransition(() => toggleClass());
t.ready.then(() => document.documentElement.animate(
{ clipPath: [`circle(0 at ${x}px ${y}px)`, `circle(${r}px at ${x}px ${y}px)`] },
{ duration: 500, pseudoElement: '::view-transition-new(root)' }
));
Why this matters for color tooling
Palette tools redraw everything on every change: swatches, gradient previews, contrast bars, exported tokens. Wrapping each apply in a view transition turns aggressive UI changes into something cinematic without any per-component animation work.
Browser support, today
Chrome, Edge, Opera and Safari 18 all ship same-document transitions. Firefox is in progress. The progressive-enhancement feature-check above means non-supporting browsers fall back to instant swaps - a degradation no one will notice.
Try the effect live: any theme toggle on this site uses View Transitions. Open Color Picker in two tabs - light and dark - and watch the difference.