'How to get element in user-agent shadow root with JavaScript?
I need get elements from Shadow DOM and change it. How i can do it?
<div>
<input type="range" min="100 $" max="3000 $">
</div>
Solution 1:[1]
Here is an example:
var container = document.querySelector('#example');
//Create shadow root !
var root = container.createShadowRoot();
root.innerHTML = '<div>Root<div class="test">Element in shadow</div></div>';
//Access the element inside the shadow !
//"container.shadowRoot" represents the youngest shadow root that is hosted on the element !
console.log(container.shadowRoot.querySelector(".test").innerHTML);
Demo:
var container = document.querySelector('#example');
//Create shadow root !
var root = container.createShadowRoot();
root.innerHTML = '<div>Root<div class="test">Element in shadow</div></div>';
//Access the element inside the shadow !
console.log(container.shadowRoot.querySelector(".test").innerHTML);
<div id="example">Element</div>
I hope this will help you.
Solution 2:[2]
You cannot access a Shadow DOM created by the browser to display a control, that is called a #shadow-root (user-agent)
in the Dev Tools. <input>
is one example.
You can only access open custom Shadow DOM (the ones that you create yourself), with the { mode: 'open' }
option.
element.attachShadow( { mode: 'open' } )
Update
It's true for most UX standard HTML elements: <input>
, <video>
, <textarea>
, <select>
, <audio>
, etc.
Solution 3:[3]
To answer (a generalized version of) the OP question:
How can you query elements, no matter if in shadowRoot or not?
It feels like the shadow root API is still lacking (or I just don't know it well enough). But it basically renders querySelectorAll
somewhat useless, in that querySelectorAll
will not actually get all matching elements anymore, since it simply ignores all ancestors in shadowRoots
. Maybe there is an API that fixes that, but just in case there is not:
Here is a simple function that recursively iterates all shadowRoots
and gets you all matching elements on the page, not just those of a single shadowRoot
.
/**
* Finds all elements in the entire page matching `selector`, even if they are in shadowRoots.
* Just like `querySelectorAll`, but automatically expand on all child `shadowRoot` elements.
* @see https://stackoverflow.com/a/71692555/2228771
*/
function querySelectorAllShadows(selector, el = document.body) {
// recurse on childShadows
const childShadows = Array.from(el.querySelectorAll('*')).
map(el => el.shadowRoot).filter(Boolean);
// console.log('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));
// fuse all results into singular, flat array
const result = Array.from(el.querySelectorAll(selector));
return result.concat(childResults).flat();
}
// examples:
querySelectorAllShadows('td'); // all `td`s in body
querySelectorAllShadows('.btn') // all `.btn`s in body
querySelectorAllShadows('a', document.querySelector('#right-nav')); // all `a`s in right menu
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ismail RBOUH |
Solution 2 | |
Solution 3 |