Basics of Shadow DOM
Table of Contents
If you work in the world of web, there's no doubt you've run into the Shadow DOM in one form or another. Even if it was hiding in the shadows and you didn't even know it was there. In this blog post I want to go over the basics of the Shadow DOM so that you can have a better understanding of what's really going on, should you ever notice one in "the wild".
Well, to start off, what even IS a Shadow DOM? Is it the DOM's shady twin brother, or perhaps some kind of alternate-evil version? For me, my mind goes right to Shadow Link from the Legend of Zelda: Ocarina of Time.
However, there is no need to fear the Shadow DOM. It actually a very helpful tool that allows complex elements to be isolated and abstracted.
What is the Shadow DOM
The Shadow DOM is an isolated and scoped DOM subtree within a web component
Basically, the Shadow DOM is an entirely separate DOM tree that branches off of an element. This separate DOM tree is completely isolated, allowing it to be protected from CSS and Javascript
4 Main parts of the Shadow DOM
Before we dive in to constructing Shadow DOMs, let's cover the basics of the 4 different parts.
Shadow Host
The shadow host is the element that the Shadow DOM is attached toShadow Tree
The shadow tree is the entirely separate structure the makes up the Shadow DOMShadow Root
The shadow root is the root node of the shadow tree that is connected to the shadow hostShadow Boundary
The shadow boundary is the line the separates the Shadow DOM from the rest of the main DOM
Here is a good visual representation of this found in the mdn web docs.
So, how are Shadow DOMs created?
Any HTML element can have a Shadow DOM attached to it. This is typically done when creating a custom HTML element. This is done by using Element.attachShadow()
Note: attachShadow() takes an option of
mode
which can be either"open"
or"closed"
You manipulate the Shadow DOM using Javascript exactly the same way you would the regular DOM.
Given the following HTML:
<html>
<body>
<p>This is not part of the Shadow DOM</p>
<div id="host">
</div>
</body>
</html>
You could do the following:
// Attach an open Shadow DOM to a host
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
// Create a p element and give it some text
const p = document.createElement("p");
p.textContent = "This is part of the Shadow DOM"
// Append the newly created element to the Shadow DOM
shadow.appendChild(p);
This would then turn our HTML into this:
<html>
<body>
<p>This is not part of the Shadow DOM</p>
<div id="host">
#shadow-root (open)
<p>This is part of the Shadow DOM</p>
</div>
</body>
</html>
Isolation of styles
So now that we see how a simple Shadow DOM is created, let's look at some of the benefits of isolation this gives us.
Remember, everything inside of the Shadow DOM is completely separate. So it will not receive any styles or javascript changes on the page.
I'll show a quick example using styles. Let's add the following styles to our page:
p {
background: #ae1f23;
border-radius: 5px;
border: solid black 1px;
box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2);
color: white;
padding: 4px;
width: fit-content;
}
As you can see, our Shadow DOM is completely untouched! And the inverse would be true too. We could've just as easily thrown special styles onto our Shadow DOM that would be isolated from the rest of the web page's styling.
Encapsulation of Javascript
As you can see here, using `document.querySelectorAll("p") to grab all the <p> elements, only gives us an array with one <p> tag. That's because the Shadow DOM is completely isolated and skipped over.
Now, that's not to say that we can't use any Javascript to manipulate our Shadow DOM.
Here we can take our host and call shadowRoot
to then do whatever we might need to with it.
However, if the shadow-root was given a {mode: "closed"}, we would not be able to access it through Javascript.
We can see that here shadowRoot returns null
:
Conclusion
So, as you can see there isn't too much that goes in to what makes up the Shadow DOM. It's an interesting tool that is useful when creating custom HTML elements. The isolation makes it nice so that we can protect it from other styles and scripts on the page.
Just in case you think you're somebody who's never come across a Shadow DOM, did you know that there are plenty of HTML elements that utilize the Shadow DOM under the hood? They use a more technical built-in Shadow DOM, so it isn't as inspectable as this one, but elements like <video>, <input type="range">, <progress>, and more all use built-in Shadow DOMs to abstract their complex parts into a simple element.
I hope you were able to learn something new and make sure you keep your eyes peeled for Shadow DOMs as you develop.
If you want to learn more about this, I highly suggest reading the mdn web docs as they cover a lot more than this post.
Photo by Rene Böhmer on Unsplash