Check out a free preview of the full Vanilla JS: You Might Not Need a Framework course:
The "Shadow DOM" Lesson is part of the full, Vanilla JS: You Might Not Need a Framework course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano discusses utilizing the shadow DOM for more control over the styling and functionality of custom elements. If a template element is on a shadow DOM, the style declarations will only apply to the template.

Get Unlimited Access Now

Transcript from the "Shadow DOM" Lesson

[00:00:00]
>> So at first it's kind of, come on. That's the first reaction, come on. So because the solution for this is to start adding classes to everything, right? Generating classitis, like the illness of adding class to everything. Well, do you understand the problem? By default this is what happens.

[00:00:23] But fortunately, we do have a solution for that, and that's the third and last part of Web Components. That's Shadow DOM. Remember, these three aspects are completely separated. In the timeline in history, they were added at different moments in different browsers. Today all of them are supporting everything.

[00:00:44] So we're good. Shadow DOM is a private, isolated DOM tree within a web component that is separated from the main document's DOM tree. You have your own DOM, your own document. And you remember that we have this option to, like translate, adopt an element from another document, we had a callback for that.

[00:01:09] This is the case where you have an element that you're moving that element from a shadow DOM to another DOM. So, it's like having kind of an iframe, but it's not really, the iframe has its own navigation. In this case, we don't have navigation, just its own DOM.

[00:01:25] And we will see that in action in a second. So the Shadow DOM then allows more control over styling and encapsulation of functionality of a custom element. By default, CSS that you declare in the main DOM, in the outer DOM, in the global DOM won't be applied to the Shadow DOM.

[00:01:45] Also that leads to some issues sometimes. So for example, if you define a font style, a font family, it won't be applied automatically to Shadow DOMs, because it's a different DOM, has its own CSS. And CSS that you declare in the Shadow DOM applies only there, not to the outside.

[00:02:09] There are ways with pseudo classes and pseudo elements that let us communicate CSS between the host and the Shadow DOM. We won't get too deep in that, okay, but just for you to know that it's possible. The Shadow DOM can be open or closed. And that defines the visibility from the outer DOM.

[00:02:33] So it's like creating a private property in Java or C#, okay? In this case, if you create an open Shadow DOM, the main DOM can get into the Shadow DOM. If you say closed, it cannot. Only JavaScript from that shadow DOM can actually get that DOM. That does make sense.

[00:02:58] And that's a property that you use when you create the Shadow DOM. We have a question. Yeah.
>> Can we reference an HTML file similar to Angular?
>> That's a good question. So the question is if we can somehow reference an external HTML file. I will answer fully the question in a minute but for now let's say that the quick answer is no.

[00:03:21] And there was an API and spec for doing that and was known as HTML imports, but let me show you how it looks like, maybe here. And can I use HTML imports? Looks like this. And as you can see, at one point we used to have green, but now it's red.

[00:03:49] So it's actually deprecated, it was removed from the spec, and it's not gonna happen, okay. But that was the way to include HTML documents for other HTML documents, for example for using it as a template. That doesn't mean that we cannot do that, in fact, we will see how to do that.

[00:04:07] But it's not like by the API. So there is no API or a spec to do that. So in this case, I'm setting all the templates in the same HTML, but we could load these templates from the outside. How? Manually. How, for example, with the Fetch API, instead of loading a JSON, you can load HTML.

[00:04:30] It is not a problem. Then we can think about performance. What happens if it doesn't load? Yeah, we need to think about lots of stuff. But yeah, you can do that. Okay, so Shadow DOM. This is how you create the Shadow DOM. You attach a Shadow DOM to the element.

[00:04:54] So this.attachShadow typically we do that in the constructor. And we said the mode open or close. And typically we store that as a property of the object to use later. It can be called root, root DOM, root Shadow, Shadow root, different names. So then when you're going to work with your own DOM now you don't append to this, you do that to the shadow DOM, make sense?

[00:05:29] Because you as web component will be part of a bigger DOM. But now you have your inner DOM inside you. So you need to work with your inner DOM, that's called the Shadow DOM, okay. Now when you have a Shadow DOM, when you have this declaration of h1, it applies only to this h1 and not for other h1 that you may have on the page, okay.

[00:05:58] Which solves the biggest issue that we saw before. So now when you have a style declarations within a web component, if you enable Shadow DOM, that is optional. If you create the Shadow DOM, then Style Sheets will apply only there, which makes a cleaner CSS code and cleaner HTML.

[00:06:19] Because you don't need to abuse on IDs and classes, mostly if the components is pretty simple. Okay, makes sense? So, answering with more information the question about where to define the HTML for custom elements. There are several alternatives, not one, and it's up to us to make the decision.

[00:06:43] We can use the DOM API's and do everything by hand, like creating the elements by hand, or in HTML. We can use a template in the main HTML. That's the option that seems like we have here. We can use an external HTML file that was the question and load it with fetch.

[00:07:01] I'll bet you're thinking well, but the first time I'm adding that element, well then we need to wait for the HTML to load while it can be prefetched. We do have a preload link element, I'm sure if you have used that. So you can prefetch in your HTML, those external files.

[00:07:21] So then when the browser needs that, it will be already in the cache. And when you have the data that is coming from an external HTML, you can use inner HTML, something known as a DOMParser that we won't cover in details today. But it's actually an object with DOM API that will parse a string and returns a document fragment that then you can inject in the real DOM.

[00:07:49] Something like that.