- From: Bramus via GitHub <noreply@w3.org>
- Date: Thu, 22 Jan 2026 09:46:47 +0000
- To: public-css-archive@w3.org
bramus has just created a new issue for https://github.com/w3c/csswg-drafts:
== [css-view-transitions-2] Figuring out whether a ViewTransition was skipped or not, is not possible ==
## The Need
There’s a bit of a gap in View Transitions, where it’s not possible for an author to, in the `finished` promise callback, know whether that promise resolved because the ViewTransition was skipped or whether the VT finished naturally.
Knowing this is necessary in cases where the author wants to do some cleanup (such as removing extra elements that were injected specifically for the View Transition). In my use-case specifically, I want to share data between the old and new VT, but that data needs to be removed when there is no more Active View Transition.
## The Issue
Take the following code _([live demo](https://codepen.io/bramus/pen/xbOryjo/e16fca3f3b2e52e468eaad8dd0d93558))_:
```js
const startVT = async () => {
// Skip the activeViewTransition if there was any
// @NOTE: This step is not really needed, as the call to startViewTransition would auto-skip it
if (document.activeViewTransition) {
document.activeViewTransition.skipTransition();
}
const t = document.startViewTransition(() => {
document.querySelector('output').innerText = performance.now();
});
await t.ready;
// … do some stuff here that relies on the pseudos being available …
t.ready
.then(() => {
console.log('READY RESOLVED')
})
// Never reached, because already awaited t.ready
.catch(() => {
console.log('READY REJECTED')
})
;
t.finished
.then(() => {
console.log('FINISHED RESOLVED')
})
.catch(() => {
console.log('FINISHED REJECTED')
})
;
};
document.querySelector('button').addEventListener('click', startVT);
```
When successively clicking the button, you’ll simply get repeated logs of the following – there are no logs of `REJECTED`:
```
READY RESOLVED
FINISHED RESOLVED
READY RESOLVED
FINISHED RESOLVED
READY RESOLVED
FINISHED RESOLVED
```
The `ready` promise’s reject-callback never gets executed, because that promise was already resolved (the `await t.ready`).
So step 7 of [the “Skip the View Transition” algorithm](https://drafts.csswg.org/css-view-transitions-1/#skip-the-view-transition-algorithm) is effectively a NO-OP:
> 7. [Reject](https://webidl.spec.whatwg.org/#reject) transition’s [ready promise](https://drafts.csswg.org/css-view-transitions-1/#viewtransition-ready-promise) with reason.
>
> NOTE: The [ready promise](https://drafts.csswg.org/css-view-transitions-1/#viewtransition-ready-promise) may already be resolved at this point, if [skipTransition()](https://drafts.csswg.org/css-view-transitions-1/#dom-viewtransition-skiptransition) is called after we start animating. In that case, this step is a no-op.
The `finished` promise of the old VT also never rejects here, because `ready` resolved. As per step 8 of [the “Skip the View Transition” algorithm](https://drafts.csswg.org/css-view-transitions-1/#skip-the-view-transition-algorithm):
> 8. [Resolve](https://webidl.spec.whatwg.org/#resolve) transition’s [finished promise](https://drafts.csswg.org/css-view-transitions-1/#viewtransition-finished-promise) with the result of [reacting](https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled) to transition’s [update callback done promise](https://drafts.csswg.org/css-view-transitions-1/#viewtransition-update-callback-done-promise)
## Trying to hack my way into a solution
I tried figuring out if a transition was skipped or not by doing the following check against `document.activeViewTransition` in the `finished` promise:
```js
if (t == document.activeViewTransition) {
// Transition was resolved Naturally
} else {
// Transition was skipped
}
```
But that also won’t work because the `activeViewTransition` gets cleared _before_ the `finish` callback gets executed, so this check is always `false`.
This is because [the “Skip the View Transition” algo from css-view-transitions-2](https://drafts.csswg.org/css-view-transitions-2/#skip-the-view-transition-algorithm) first clears the active view transition before resolving `finished`:
> 5. If document’s [active view transition](https://drafts.csswg.org/css-view-transitions-2/#document-active-view-transition) is transition, [Clear view transition](https://drafts.csswg.org/css-view-transitions-2/#clear-view-transition) transition.
> …
> 8. [Resolve](https://webidl.spec.whatwg.org/#resolve) transition’s [finished promise](https://drafts.csswg.org/css-view-transitions-2/#viewtransition-finished-promise) with the result of [reacting](https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled) to transition’s [update callback done promise](https://drafts.csswg.org/css-view-transitions-2/#viewtransition-update-callback-done-promise)
It is the last step of [the “Clear view transition” algo](https://drafts.csswg.org/css-view-transitions-2/#clear-view-transition) that clears the active view transition:
> 6. Set document’s [active view transition](https://drafts.csswg.org/css-view-transitions-2/#document-active-view-transition) to null.
## Possible solutions
As it doesn’t seem solvable in userland code, I think this needs to be solved at the spec level. Turning to possible solutions, I can think of the following suggestions:
1. Move “Set document’s active view transition to null” out of “Clear the View Transition” and place it after step 8 of “Skip the View Transition”
2. Pass some data into `finished` to indicate whether the transition was skipped or not.
Maybe anyone else has better ideas?
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13379 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Thursday, 22 January 2026 09:46:47 UTC