I'm having trouble getting JavaScript to run properly within Shadow DOM elements I'm defining. Given the following code:
<template id='testTemplate'>
<div id='test'>Click to say hi</div>
<script>
var elem = document.querySelector('#test');
elem.addEventListener('click', function(e) {
alert("Hi there");
});
</script>
</template>
<div id="testElement">Host text</div>
<script>
var shadow = document.querySelector('#testElement').createShadowRoot();
var template = document.querySelector('#testTemplate');
shadow.appendChild(template.content.cloneNode(true));
</script>
document.querySelector is returning null. If I wrap it in document.onload it no longer throws the error, but clicking the div doesn't launch the alert, either.
To access these Shadow DOM elements, we need to use the JavascriptExecutor executeScript() function. If you look at the DOM structure, every element that includes Shadow DOM also has a shadowRoot property that describes the underlying elements.
First off, it's true that shadow DOM can improve style performance, so our theory about style encapsulation holds up. However, ID and class selectors are fast enough that actually it doesn't matter much whether shadow DOM is used or not – in fact, they're slightly faster without shadow DOM.
Shadow DOM is very important for web components because it allows specific sections of the HTML document to be completely isolated from the rest of the document. This means CSS styles that are applied to the DOM are not applied to the Shadow DOM, and vice versa.
Shadow DOM permits encapsulation of styling rules for custom elements. You can freely define styling information for your elements, such as fonts, text colors, and classes, without fear of the styles applying outside the scope of your element.
You must bind your eventHandler inside the template tag to #testElement
:
var elem = document.querySelector('#testElement');
Meaning to the original element / ShadowHost. That is, because Events from ShadowElements appear as if they originated by the ShadowHost.
Javascript is actually not scoped inside of ShadowDOM-Trees. See for example this blog entry, which covers exactly that topic:
Remember when I spent all of that time explaining how Shadow DOM CSS was encapsulated and protected from the parent document and how awesome that all was? You might also think that JavaScript works the same way—I did at first—but that’s actually not the case. [...] https://robdodson.me/shadow-dom-javascript/
As an explanation for rearranging the events to the ShadowHost the author writes:
This is because events coming from shadow nodes have to be retargeted otherwise they would break encapsulation. If the event target continued to point at
#shadow-text
then anyone could dig around inside of our Shadow DOM and start messing things up. https://robdodson.me/shadow-dom-javascript/
I suppose it is a good idea to read other articles of this blog too, as it seems to cover the topic pretty well.
With custom HTML elements you have the ability to use Javascript inside of custom HTML elements, see for example this answer on Stackoverflow.
Basically you must create a complete new HTML element. A tutorial is available at html5rocks. I think this is how for example the Polymer project provides its custom events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With