View Transitions: Careful Not To Make Stuff Unclickable
View Transitions: Careful Not To Make Stuff Unclickable êŽë š
Just a little Public Service Announcement here.
Letâs say youâre doing a View Transition in the form of using the .startViewTransition() method. Maybe youâre showing an image bigger (CodePenTemplates) or sorting a table or moving some list items around (chriscoyier) or something.
If you donât deal with it specifically, itâs likely youâre blocking interactivity on the rest of the page.
Hereâs a very basic demo. There is an alert() button you can click to see an alert. Click that and see. Then run the View Transition and try to click that button.
See how you canât click the alert button while the View Transition is running?
Because of the long 10s duration in that example, it should give you enough time to open DevTools and take a peek. You should be able to see the View Transition Pseudo Tree there. And if you hover over the top one, the ::view-transition, youâll see it cover the entire viewport in light blue, telling you the dimensions of it cover the entire viewport.

So now youâve got this big, giant, invisible element covering the entire viewport for the entire length of the transition. Thatâs what stops the interactivity, like clicking.
The Solution
Two-parter here.
One, the :root element has a view-transition-name by default, so itâs going to take part in the overall View Transition even if it doesnât really do anything. I think this is a default so that entire pages can cross-fade in multi-page View Transitions. But we donât need that. So if we remove the name, it wonât be one of the snap-shotted elements taking up space.
Two, the ::view-transition element is also that big giant viewport-covering element, and what we need to do there is make sure you can click through it.
:root {
view-transition-name: none;
}
::view-transition {
pointer-events: none;
}
The snap-shotted (for lack of a better term) elements you actually see transitioning on a page are essentially on the âtop layerâ while the View Transition is happening. So theyâll soak up clicks while they are there. Not sure why thatâs the default, but thatâs what we got.
Another Newer Solution
Another solution here is the âscope downâ the View Transition. We donât have to call document.startViewTransition() (like, on the document) although that definitely has the best browser support. Instead, we can call that method on the element that has the elements inside it that we care to transition. LikeâŠ
const parent = document.querySelector("#parent");
move.addEventListener("click", () => {
parent.startViewTransition(() => {
thing.classList.toggle("moved");
})
});
Scoped view transitions are just a good idea, allowing for things like keeping elements in a hidden overflow area and such (because the pseudo-element tree stays within that parent element). We also benefit here as, without doing any other CSS manipulation, interactive elements arenât affected. You still might wanna do the CSS stuff, though, if you want to retain interactivity within the scoped area.