Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript within Shadow DOM best practices

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.

  1. Is document.onload the proper way to handle when my code runs in this case?
  2. Is this the proper way to embed javascript for shadow dom elements?
like image 745
anderspitman Avatar asked Jul 30 '14 23:07

anderspitman


People also ask

How do you handle shadow DOM elements?

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.

Does shadow DOM improve performance?

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.

Should I use 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.

Can you style shadow DOM?

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.


1 Answers

Shadow DOM tree

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.

Custom elements

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.

like image 134
Ulrich Thomas Gabor Avatar answered Oct 17 '22 21:10

Ulrich Thomas Gabor