From 7ec530e1d928459b35101bc4e1b9b08f56a9edaa Mon Sep 17 00:00:00 2001 From: MichaelWest22 Date: Thu, 4 Sep 2025 01:01:53 +1200 Subject: [PATCH] fix issue with hx-sync and htmx:abort with shadow DOM --- src/htmx.js | 2 +- test/core/shadowdom.js | 60 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/htmx.js b/src/htmx.js index aa9908f9b..016ae7cd9 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -5116,7 +5116,7 @@ var htmx = (function() { "[hx-trigger='restored'],[data-hx-trigger='restored']" ) body.addEventListener('htmx:abort', function(evt) { - const target = evt.target + const target = (/** @type {CustomEvent} */(evt)).detail.elt || evt.target const internalData = getInternalData(target) if (internalData && internalData.xhr) { internalData.xhr.abort() diff --git a/test/core/shadowdom.js b/test/core/shadowdom.js index ec2ca0f93..d38ab5017 100644 --- a/test/core/shadowdom.js +++ b/test/core/shadowdom.js @@ -1341,4 +1341,64 @@ describe('Core htmx Shadow DOM Tests', function() { getWorkArea().innerHTML.should.equal('Clicked!') chai.expect(getWorkArea().shadowRoot).to.be.a('null') }) + + it('hx-sync works properly in shadow DOM', function() { + var count = 0 + this.server.respondWith('GET', '/test', function(xhr) { + xhr.respond(200, {}, 'Click ' + count++) + }) + make('
' + + '
') + var b1 = byId('b1') + var b2 = byId('b2') + b1.click() + b2.click() + this.server.respond() + this.server.respond() + b1.innerHTML.should.equal('Click 0') + b2.innerHTML.should.equal('Initial') + }) + + it('can abort a request programmatically in shadow DOM', function() { + var count = 0 + var abortedCount = 0 + this.server.respondWith('GET', '/test', function(xhr) { + xhr.respond(200, {}, 'Click ' + count++) + }) + make('
' + + '
') + var b1 = byId('b1') + var b2 = byId('b2') + + // Listen for abort events to verify they're working + htmx.on(b1, 'htmx:abort', function() { abortedCount++ }) + + b1.click() + b2.click() + + htmx.trigger(b1, 'htmx:abort') + + this.server.respond() + this.server.respond() + b1.innerHTML.should.equal('Initial') + b2.innerHTML.should.equal('Click 0') + abortedCount.should.equal(1) + }) + + it('hx-sync abort strategy works in shadow DOM', function() { + var count = 0 + this.server.respondWith('GET', '/test', function(xhr) { + xhr.respond(200, {}, 'Click ' + count++) + }) + make('
' + + '
') + var b1 = byId('b1') + var b2 = byId('b2') + b1.click() + b2.click() + this.server.respond() + this.server.respond() + b1.innerHTML.should.equal('Initial') + b2.innerHTML.should.equal('Click 0') + }) })