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):
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')
})
.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
Normally, when skipping a transition, the ready promise rejects … but only when it was not resolved yet, as detailed in step 7 of the “Skip the View Transition” algorithm:
-
Reject transition’s ready promise with reason.
NOTE: The ready promise may already be resolved at this point, if skipTransition() is called after we start animating. In that case, this step is a no-op.
Because the ready promise already resolved (the await t.ready;), step 7 is the no-op as mentioned in the note.
(You can also remove the await t.ready; and still have this behavior. It resolves really fast because it all happens in under a frame)
Furthermore the finished promise of the old VT also never rejects, because updateCallbackDone also resolved by that time. As per step 8 of the “Skip the View Transition” algorithm:
- Resolve transition’s finished promise with the result of reacting to transition’s 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:
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 first clears the active view transition before resolving finished:
- If document’s active view transition is transition, Clear view transition transition.
…
- Resolve transition’s finished promise with the result of reacting to transition’s update callback done promise
It is the last step of the “Clear view transition” algo that clears the active view transition:
- Set document’s 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:
- Move “Set document’s active view transition to null” out of the “Clear the View Transition” algo and place it after step 8 of the “Skip the View Transition” algo. That way the
finished promise can check against document.activeViewTransition.
- Pass some data into
finished to indicate whether the transition was skipped or not.
- [insert your idea here]
The Need
There’s a bit of a gap in View Transitions, where it’s not possible for an author to, in the
finishedpromise 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):
When successively clicking the button, you’ll simply get repeated logs of the following – there are no logs of
REJECTED:Normally, when skipping a transition, the
readypromise rejects … but only when it was not resolved yet, as detailed in step 7 of the “Skip the View Transition” algorithm:Because the
readypromise already resolved (theawait t.ready;), step 7 is the no-op as mentioned in the note.(You can also remove the
await t.ready;and still have this behavior. It resolves really fast because it all happens in under a frame)Furthermore the
finishedpromise of the old VT also never rejects, becauseupdateCallbackDonealso resolved by that time. As per step 8 of the “Skip the View Transition” algorithm: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.activeViewTransitionin thefinishedpromise:But that also won’t work because the
activeViewTransitiongets cleared before thefinishcallback gets executed, so this check is alwaysfalse.This is because the “Skip the View Transition” algo from css-view-transitions-2 first clears the active view transition before resolving
finished:It is the last step of the “Clear view transition” algo that clears the active view transition:
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:
finishedpromise can check againstdocument.activeViewTransition.finishedto indicate whether the transition was skipped or not.