'How to select element inside open Shadow DOM from Document?
Say I have a DOM that looks like this in my Document:
<body>
<div id="outer">
<custom-web-component>
#shadow-root (open)
<div id="inner">Select Me</div>
</custom-web-component>
</div>
</body>
Is it possible to select the inner div inside the shadow root using a single querySelector
argument on document
? If so, how is it constructed?
For example, something like document.querySelector('custom-web-component > #inner')
Solution 1:[1]
you can do it like this:
document.querySelector("custom-web-component").shadowRoot.querySelector("#inner")
Solution 2:[2]
In short, not quite. The TL:DR is that, depending on how the component is set up, you might be able to do something like this:
document.querySelector('custom-web-component').div.innerHTML = 'Hello world!';
Do do this - if you have access to where the web component is created, you can add an interface there to access inner content. You can do this the same way you would make any JavaScript class variable/method public. Something like:
/**
* Example web component
*/
class MyComponent extends HTMLElement {
constructor() {
super();
// Create shadow DOM
this._shadowRoot = this.attachShadow({mode: 'open'});
// Create mock div - this will be directly accessible from outside the component
this.div = document.createElement('div');
// And this span will not
let span = document.createElement('span');
// Append div and span to shadowRoot
this._shadowRoot.appendChild(span);
this._shadowRoot.appendChild(this.div);
}
}
// Register component
window.customElements.define('custom-web-component', MyComponent);
// You can now access the component 'div' from outside of a web component, like so:
(function() {
let component = document.querySelector('custom-web-component');
// Edit div
component.div.innerHTML = 'EDITED';
// Edit span
component._shadowRoot.querySelector('span').innerHTML = 'EDITED 2';
})();
<custom-web-component></custom-web-component>
In this instance, you can access the div
from outside of the component, but the span
is not accessible.
To add: As web components are encapsulated, I don't think you can otherwise select internal parts of the component - you have to explicitly set a way of selecting them using this
, as above.
EDIT:
Saying that, if you know what the shadow root key is, you can do this: component._shadowRoot.querySelector()
(added to demo above). But then that is quite a weird thing to do, as it sorta goes against the idea of encapsulation.
EDIT 2
The above method will only work is the shadow root is set using the this
keyword. If the shadow root is set as let shadowRoot = this.attachShadow({mode: 'open'})
then I don't think you will be able to search for the span
- may be wrong there though.
Solution 3:[3]
This code will behave like query selector and work on nested shadowDoms:
const querySelectorAll = (node,selector) => {
const nodes = [...node.querySelectorAll(selector)],
nodeIterator = document.createNodeIterator(node, Node.ELEMENT_NODE);
let currentNode;
while (currentNode = nodeIterator.nextNode()) {
if(currentNode.shadowRoot) {
nodes.push(...querySelectorAll(currentNode.shadowRoot,selector));
}
}
return nodes;
}
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 | Ruben |
Solution 2 | |
Solution 3 | AnyWhichWay |