From cd1ed94623c7777e33822b826c038dbaa9a127a4 Mon Sep 17 00:00:00 2001 From: James Barlow <332269+manwithacat@users.noreply.github.com> Date: Mon, 7 Sep 2026 21:56:55 +0100 Subject: [PATCH] fix: handle skipped view transition ready rejection document.startViewTransition().ready rejects when the document is hidden. Catching only .finished left an unhandledrejection even though the swap still completed. Closes #3989 --- src/htmx.js | 6 +++++- test/tests/unit/swap.js | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/htmx.js b/src/htmx.js index 7f444c11c..8f2c10c26 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -2288,7 +2288,11 @@ var htmx = (() => { if (document.startViewTransition) { let detail = {task, ctx}; this.__trigger(ctx.sourceElement, "htmx:before:viewTransition", detail) - await document.startViewTransition(detail.task).finished; + let vt = document.startViewTransition(detail.task); + // ready rejects when the document is hidden; unfinished catch + // still produces unhandledrejection unless we handle ready too + vt.ready?.catch(() => {}); + await vt.finished; this.__trigger(ctx.sourceElement, "htmx:after:viewTransition", detail) } else { await task(); diff --git a/test/tests/unit/swap.js b/test/tests/unit/swap.js index 987118d32..38ee58477 100644 --- a/test/tests/unit/swap.js +++ b/test/tests/unit/swap.js @@ -879,6 +879,30 @@ describe('swap() unit tests', function() { assert.isTrue(true); }) + it('does not emit unhandledrejection when view transition ready rejects', async function() { + let unhandled = 0; + let onUnhandled = () => { unhandled++; }; + window.addEventListener('unhandledrejection', onUnhandled); + const originalStartViewTransition = document.startViewTransition; + document.startViewTransition = (cb) => { + let finished = Promise.resolve().then(() => cb()); + let ready = Promise.reject(new DOMException('Skipped ViewTransition due to document being hidden', 'InvalidStateError')); + return { ready, finished, skipped: Promise.resolve(), updateCallbackDone: finished }; + }; + try { + await htmx.swap({ + target: "#test-playground", + text: "