From 9b231665d04a7ae9e6cbeeb2c026fa0fa065dd0a Mon Sep 17 00:00:00 2001 From: Luke Warlow Date: Wed, 2 Jul 2025 12:43:59 +0100 Subject: [PATCH] Support Declarative Shadow DOM --- src/morphdom.js | 6 +++++- src/util.js | 12 ++++++++++-- test/browser/test.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/morphdom.js b/src/morphdom.js index f978372..0e35612 100644 --- a/src/morphdom.js +++ b/src/morphdom.js @@ -27,7 +27,11 @@ export default function morphdomFactory(morphAttrs) { if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') { var toNodeHtml = toNode; toNode = doc.createElement('html'); - toNode.innerHTML = toNodeHtml; + if (toNode.setHTMLUnsafe) { + toNode.setHTMLUnsafe(toNodeHtml); + } else { + toNode.innerHTML = toNodeHtml; + } } else { toNode = toElement(toNode); } diff --git a/src/util.js b/src/util.js index 3ed233c..9b6d4de 100644 --- a/src/util.js +++ b/src/util.js @@ -7,7 +7,11 @@ var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' i function createFragmentFromTemplate(str) { var template = doc.createElement('template'); - template.innerHTML = str; + if (template.setHTMLUnsafe) { + template.setHTMLUnsafe(str); + } else { + template.innerHTML = str; + } return template.content.childNodes[0]; } @@ -23,7 +27,11 @@ function createFragmentFromRange(str) { function createFragmentFromWrap(str) { var fragment = doc.createElement('body'); - fragment.innerHTML = str; + if (fragment.setHTMLUnsafe) { + fragment.setHTMLUnsafe(str); + } else { + fragment.innerHTML = str; + } return fragment.childNodes[0]; } diff --git a/test/browser/test.js b/test/browser/test.js index 146d4be..43eed41 100644 --- a/test/browser/test.js +++ b/test/browser/test.js @@ -1677,4 +1677,34 @@ describe('morphdom' , function() { expect(div1).to.equal(div1_2); }); + + it('should handle declarative shadow dom', function() { + // Initial state: simple div with some content + const el1 = document.createElement('div'); + el1.innerHTML = '

Before

'; + + // Target HTML includes declarative shadow DOM + const newHTML = ` +
+ + + +
`; + + // Perform the morph + morphdom(el1, newHTML); + + // The shadow root should now exist + const shadowRoot = el1.firstElementChild.shadowRoot; + expect(shadowRoot === null).to.equal(false); + expect(shadowRoot.mode).to.equal('open'); + + // The shadow DOM should contain the expected content + expect(shadowRoot.innerHTML.trim()).to.equal('Inside Shadow'); + + // The light DOM should have no children (template was processed and removed) + expect(el1.firstElementChild.children.length).to.equal(0); + }); });