Hello! Let's talk about the shadow DOM.
What is the Shadow DOM? Let's first look at a video.
You know the video element, we already used many times in this course.
If you look at the source of the video element, or if you try to select it using the devtools, you can only select it at once, you can't select individually the buttons, or the progress element, and so on.
Look at the video, you see the video controls, autoplay, source elements, and so on.
But you can’t look at the internals because this video is a Web component.
Web components have been used by browser developers before the APIs went public.
You can enable in the settings (I am using Google Chrome here), you can enable the visualization of the user agent shadow DOM.
When this option is enabled, then you will see a shadow root in the debugger, when you look for a Web component.
This time, if I open the shadow root in the debugger, and if I move the inspector, I can see how the Web component is made.
I can see its internals.
I can look at the play button for example.
The shadow DOM is a way to hide HTML code from the end user.
If you do ‘view source’, you will not see how a Web Component is made, except if you set the correct debugging settings option.
More than that, the Web component may include some CSS files and the CSS of the Web component will only apply to its own elements.
Let's look at an example.
Here, we(ve got a button that is called ‘a shadow host’.
This is our Web component.
For the moment we are not using custom elements, we are just associating a shadow DOM with the button element here.
This one is called ’the host’, and as you can see it is not rendered because it has a shadow DOM.
So, the way we add a shadow DOM to an element is that we first select the host, and then we create a shadow root.
Once you got the shadow root, you can start adding content in this node, in order to make the shadow DOM.
So here, ‘root.textContent’ will add this text to the shadow DOM and if you look at the button, this is the text that is rendered: ’Hello’.
If I inspect this element using the devtools, I will see a button, and a shadow root associated.
In another example in the course, we will talk about templates and shadow DOM.
Instead of adding just text in the shadow DOM using textContent or innerHTML, we can clone a template.
So in this example, I’ve got a template that contains a ‘H1’.
This is a ‘shadowed H1’ and some CSS style defined in the template.
When I create the root element for the shadow DOM, I can append the cloned code of the template.
In this case I have got a skeleton: the template.
I instantiate it and I add it to the shadow DOM.
Look at the result here! I have got my host (that is a ‘H1’), and if I type things it is not rendered.
What is rendered is the content here of the template I instantiated.
And this template contains an ‘H1’ that is white on red.
But look: I have got a global CSS that says that all ‘H1s’ must be green, and this one is not affected, it does not cross the boundaries of the Web component.
The same thing is true for the style in the Web component, that says that all ‘H1s’ must be white on red, and it does not affect the ‘H1’ in the page.
I added an ‘H1’ that is not associated with the shadow DOM and this one is impacted by the normal CSS style that says that the color is green for each ‘H1’.
This one is green but not the once inside the shadow DOM.
So it is good for encapsulation: you can protect your widget (your Web component) so that external CSS will not affect it.
In the next lesson, we will see how we can allow some style to cross the boundaries, but under control.
This is all for this video! Bye! Bye!
The Shadow DOM API provides DOM encapsulation: it serves to hide what is not necessary to see!
It is not obvious but the Shadow DOM API is already used by browsers' developers for <audio> or <video> elements, and also for the new <input type="date">, <input type="color"> elements, etc.
NB: Because other browsers do not offer the tool-set, all of the examples we discuss on this subject use Google Chrome or Chromium.
Let's have a look at a simple <video> element.
Open this JSBin example in your browser, and fire up the devtools console (F12 on Windows/Linux, Cmd-Alt-i on Mac OS):
Click on the "Elements" tab in the devtools, or use the magnifying glass and click on the video, to look at the DOM view of the video element. You will see the exact HTML code that is in this example, but you cannot see the elements that compose the control bar. You don't have access to the play button, etc.
Let's take a look behind the scenes, and see the Shadow DOM associated with the <video> element.
First, click on the Settings icon (three vertical dots) and select Settings in the drop down menu:
Then scroll down until you see the "Show user agent shadow DOM" option and check it. Close the panel.
Now, look for the video element again and within the DOM view you should see something new:
Open this shadow root by clicking on it, and move the mouse pointer over the different elements:
Chrome developers are already using the shadow DOM to define their own Web Components, such as <video> or <audio> elements! And they use the Shadow DOM to hide the internal plumbing.
Furthermore, there is a kind of "boundary" around the <video> element, so that external CSS cannot interfere. The content of the <video> element is sandboxed (protected from external CSS selectors, for example, or cannot be accessed using document.querySelector(), nor inspected by default, using a DOM inspector). Find further reading on the concept of sandboxing.
Let's have a look at a very simple example:
<div>Hello this is not rendered!</div>
<script>
// the div is the Shadow Host. Its content will not be rendered
var host = document.querySelector('div');
// Create the shadow ROOT, the root node of the shadow DOM
// using mode:open makes it available, mode:close would return null
const shadowRoot = host.attachShadow({mode: 'open'});
// insert something into the shadow DOM, this will be rendered
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>'; // Could also use appendChild().
</script>
Lines 8 and 11 show how to associate a shadow root with an existing HTML element. In this example, the <div> defined at line 1 is a shadow host, and it is associated with the shadow root which contains three words of text (line 11).
This example illustrates the three rules of the shadow DOM. Let's look at them again:
The three rules of Shadow DOM:
With Shadow DOM, elements are associated with a new kind of node: a shadow root.
An element in the HTML which has a shadow root associated with it is called a shadow host.
The content of a shadow host doesn’t appear; the content of the shadow root is rendered instead.
And indeed, the above example (try the online version here at JSBin) renders the content of the shadow root, not the content of the button. In the online example, try to change the text of the div (line 1), and you will notice that nothing changes. Then modify the text at line 11 and observe the result