What's a ShadowDOM?
I first came to know about Shadow DOM from my curiosity about how browsers implement tags like <video> with all the controllers or <input> which changes based on the type attribute. We can never see any HTML code for these implementation and yet they are shown. How? That is when I stumbled upon this blog by Dimitri Glazkov which explains beautifully the concept of shadow DOM encapsulation used by browsers to implement such tags.
However, none of the browsers allowed developers to write their own custom shadow DOM (though google chrome had a v0 version implemented). I stumbled upon shadow DOM again while looking at an issue in jQuery to fix. So now, since 2018, most of the browsers have started supporting shadow DOM APIs and hence jQuery needed to implement support for that too.
| |
| https://caniuse.com/#feat=shadowdomv1 |
So, what is this shadow DOM and why do we even use it?
What's a DOM?
W3C specification describes it as "a method of combining multiple DOM trees into one hierarchy and how these trees interact with each other within a document, thus enabling better composition of the DOM".
Now, to understand that, we need to understand what a DOM is. DOM or Document Object Model is a tree-like structure containing the different elements (or tags) and strings of text that are shown by the markup language (like HTML, XML, etc.).
So, let's say we have a HTML code something like this:
\<!DOCTYPE html\>
\<html\> \<head\> \<meta charset="utf-8"\> \<title\>Title\</title\> \</head\> \<body\> \<div\> \<h1\>This is header\</h1\> \<p\>This is a \<a href="https://www.saptaks.blog"\> link \</a\> \</p\> \</div\> \</body\>
\</html\>
So, visually you can show the DOM structure as something like:
Shadow DOM
Now, shadow DOM allows us to create separate hidden DOM trees that are attached to the elements of a regular DOM tree. This allows you to implement functional encapsulation, i.e. someone parsing the regular DOM tree and applying styling to the regular DOM tree doesn't know or affect the properties and functionalities of the shadow DOM tree. Hence you use the shadow DOM without knowing the intricate details of how the DOM is implemented. This is important, because this follows the basic ideas of Object Oriented Programming.
The shadow DOM tree starts with a shadow root and can then have any regular DOM element attached underneath it.
Let's see an example: HTML
\<!DOCTYPE html\>
\<html\> \<head\> \<meta charset="utf-8"\> \<title\>Title\</title\> \</head\> \<body\> \<div id="shadowHost"\> \</div\> \</body\>
\</html\>
JavaScript
const shadowHost = document.getElementById('shadowHost');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '\<h1\>Hello Shadow DOM\</h1\>';
So, this will create a shadow DOM. Visually you can represent this as:
So, as you can see, there are few different parts in a shadow DOM apart from it being just another DOM.
- Shadow tree : The DOM tree inside the shadow DOM.
- Shadow boundary : the place where the shadow DOM ends, and the regular DOM begins.
- Shadow root : The root node of the shadow tree.
- Shadow host : The regular DOM node that the shadow DOM is attached to.
- Shadow child : The tree below the shadow root node.
The shadow DOM cannot be attached to few different elements as mentioned in the spec. Some of the reasons are:
- The different form tags such as <input>, <textarea>, etc or any other html tag for which the browser implements it's own Shadow DOM
- Elements like <img> or <br> or <hr> which are usually self enclosing tags and don't usually contain a child node.
Also if you see in the code there is a "{mode: open}". The mode determines whether you can edit the style of the shadow DOM from outside the shadow DOM or not.
Why do we need Shadow DOM anyways?
There are few different scenarios where you might want to use shadow DOM. The most important functionality of shadow DOM is the implementation of the concept of encapsulation. So basically, someone using the shadow DOM host doesn't need to care the style and implementation of the DOM inside. So few use-cases would be following:
- The browser implements Shadow DOM for various different tags such as <video>, <audio>, <input>, <select>, etc.
- You can make your own custom Shadow DOM when you need to create an element that you want to not be modified by the styling of remaining DOM.
- You can also use Shadow DOM, when you want to create a separation of a particular DOM element from the main DOM element.
So is Shadow DOM very shadow-ey? Well maybe, since it stays hidden from the main DOM traversal. But at the same time it is often very useful because of it's encapsulation properties.