Demystifying Shadow DOM

Demystifying Shadow DOM

DOM

Before we dive into shadow DOM, let's rewind what a DOM is. According to the definition, the DOM is a Programming Interface that allows the interaction with the structure, style, and content of a web page. The DOM parser parses the HTML/XML Document and creates a tree-like structure where each element in the tree is called a node. Likewise, the CSSOM parser parses the stylesheets/inline styles and creates a tree-like structure similar to DOM where-in each node contains the required style information. Finally, the outputs of DOM and CSSOM parsers are combined together, and the render tree is built which beautifully displays the content in the webpage.

Shadow DOM

Shadow DOM is an encapsulated DOM that is rendered separately from the main document. The script and styling present in the shadow DOM are private to the shadow DOM. This means that document.querySelector() will not return the Shadow DOM elements. The styles added to the shadow DOM will not leak outside of the Shadow DOM and the outside styles will not leak inside the shadow DOM. Therefore, you can apply styles directly to the generic selectors, ids, and classes without worrying about the conflicts. Shadow DOM provides both DOM and Style encapsulation.

Shadow DOM vs Virtual DOM

A few frameworks such as React.js, Vue.js make use of Virtual DOM to optimize the performance. React.js creates a copy of the real DOM and saves it in the memory. This copied version is called Virtual DOM. React.js doesn't update the real DOM directly. It runs a diffing algorithm to find out the changes. Whenever the state changes, React.js compares Virtual DOM with its previous versions. If it finds any, it updates only those changes into the real DOM. This process is called Reconciliation. So, the virtual DOM is used for improving performance and the Shadow DOM is used for encapsulation. You can create virtual DOM and attach it to shadow DOM or vice versa.

Are Web components and shadow DOM the same?

No. Shadow DOM is the technology used in Web components. Web components are developed on top of shadow DOM. They make use of encapsulation provided by shadow DOM. They provide the set of APIs using which we can create encapsulated, reusable, custom elements. These components are framework agnostic that can be used across all javascript applications.

Difference between web components and components created by Vue.js, React, Angular

  1. DOM encapsulation: As I said earlier, the difference lies in the encapsulation part. Although the frameworks support component reusability, a component will still have access to elements in other components using query selector APIs (document.querySelector()). In the case of Web components, each component is strongly encapsulated and can only be accessed within the shadow DOM. document.querySelector() does not return the elements on other web components.

  2. Style encapsulation: The frameworks like Vue.js and React.js don't support style encapsulation natively. For vue.js, vue-loader supports scoped attribute for style tags. Other frameworks make use of css modules, css-in-js libraries to handle style encapsulation. However,Angular supports emulated style encapsulation. It provides an option called [encapsulation] (angular.io/api/core/ViewEncapsulation) in the component API.

Building blocks of shadow DOM

  1. Shadow host - The shadow host is the same as the other child nodes attached to the real DOM. It can be div, span, or anything in this list. <text-area>, <input /> have their own shadow DOM built-in by the browser.
  2. Shadow tree - The DOM tree inside the shadow DOM
  3. Shadow root - The root node of the Shadow tree

Shadow DOM looks like below,

image.png

HTML Structure

image.png

Creating Shadow DOM

const shadowHost = document.createElement('div');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowHost.id = 'shadow-host';
shadowRoot.innerHTML = `
<h1>Hi, there!/h1>
<style>
   h1 {
     color: green;
   }
</style>`;

Hence, any element that calls attachShadow will become a shadow host and create a shadow tree. In the above code, the mode is set to open. If the shadow root is created with open mode, the shadow root can be accessed by the real DOM elements in the following way,

document.querySelector('#shadow-host').shadowRoot.innerHTML

If the mode is set to closed, the above code will return null.

Browser compatibility

Shadow DOM is supported by the latest browsers such as Chrome, Firefox (63 and onwards), Opera, Safari, and Edge. The polyfills are also available for the unsupporting browsers.