2

I would like to get plain HTML with shadowRoot elements extracted. There is a lot of shadowRoot elements on a website and are deeply nested.

I use that piece of code to achieve it. But it only extracts some of the elements

const getShadowDomHtml = (shadowRoot) => {
    let shadowHTML = '';
    for (let el of shadowRoot.childNodes) {
        shadowHTML += el.nodeValue || el.outerHTML;
    }
    return shadowHTML;
};


const replaceShadowDomsWithHtml = (rootElement) => {
    for (let el of rootElement.querySelectorAll('*')) {
        if (el.shadowRoot) {
            replaceShadowDomsWithHtml(el.shadowRoot);
            el.innerHTML += getShadowDomHtml(el.shadowRoot);
        }
    }
};

.

> replaceShadowDomsWithHtml(document.body);

.

> document.body.innerHTML
Blaze
  • 79
  • 6
  • The "duplicate" question is not a duplicate. This is about getting the entire HTML content of a tree containing shadowRoots. The other question is about finding an element in a tree that has shadowRoots. The solutions given here are not adequate and I have made a better one. – Moss Nov 06 '21 at 20:15

2 Answers2

1

OK, I've found and customize code that works for me

const recursiveWalk = (node, func) => {
    const done = func(node);
    if (done) {
        return true;
    }

    if ('shadowRoot' in node && node.shadowRoot) {
        const done = recursiveWalk(node.shadowRoot, func);
        if (done) {
            return true;
        }
    }
    node = node.firstChild;

    while (node) {
        const done = recursiveWalk(node, func);
        if (done) {
            return true;
        }
        node = node.nextSibling;
    }
}

let html = '';

recursiveWalk(document.body, function (node) {
    html += node.nodeValue || node.outerHTML;
});

console.log(html);
Blaze
  • 79
  • 6
0

When creating a Shadow DOM, the developper specifies a mode when attaching it to an element: open or closed.

open ones are extracted, closed ones don't.

Look at the snippet below, you'll get an error because a closed DOM's root can't be accessed without a reference. Call the shadowRoot property of a closed DOM and it will return null.

const open = document.querySelector('#open'),
  closed = document.querySelector('#closed');
  
// Open
const openShadowRoot = open.attachShadow({ mode: "open" });
openShadowRoot.innerHTML = '<p>Open Shadow Root</p>'

// Closed
const closedShadowRoot = closed.attachShadow({ mode: "closed" });
closedShadowRoot.innerHTML = '<p>Closed Shadow Root</p>'

// Gets shadow roots
for (let el of document.querySelectorAll('div')) {
  console.log(el.shadowRoot.innerHTML);
}
<div id="open"></div>
<div id="closed"></div>

So I guess that some of them are closed, while the others don't.

Kévin Bibollet
  • 3,573
  • 1
  • 15
  • 33