paint-brush
Declarative Shadow DOM: The Magic Pill for Server-Side Rendering and Web Componentsby@pradeepin2
New Story

Declarative Shadow DOM: The Magic Pill for Server-Side Rendering and Web Components

by Pradeep Kumar SaraswathiJuly 31st, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Shadow DOM is a web standard enabling encapsulation of DOM subtrees in web components. It allows developers to create isolated scopes for CSS and JavaScript within a document, preventing conflicts with other parts of the page. Shadow DOM's key feature is its "shadow root," serving as a boundary between the component's internal structure and the rest of the document.
featured image - Declarative Shadow DOM: The Magic Pill for Server-Side Rendering and Web Components
Pradeep Kumar Saraswathi HackerNoon profile picture


Server Side Rendering Web components

Generating static HTML from JavaScript on the server called Server Side Rendering is a technique used to improve the perceived performance, SEO, and support for non-scripting environments.


Shadow DOM:

Shadow DOM is a web standard enabling the encapsulation of DOM subtrees in web components, shielding them from external styling and manipulation. It allows developers to create isolated scopes for CSS and JavaScript within a document, preventing conflicts with other parts of the page. Shadow DOM's key feature is its "shadow root," serving as a boundary between the component's internal structure and the rest of the document. This enables building modular, reusable components with their own encapsulated styles and behavior, enhancing code maintainability and reducing the risk of unintended side effects in complex web applications.


Here is the sample code of the web component with Shadow DOM


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Shadow DOM Example</title>
</head>
<body>
  <div id="parent"></div>

  <script>
    // Create a shadow DOM for the container element
    const container = document.getElementById('parent');
    const shadowRoot = container.attachShadow({ mode: 'open' });

    // Create an element inside the shadow DOM
    const paragraph = document.createElement('p');
    paragraph.textContent = 'This paragraph text is inside the Shadow DOM.';
    
    // Apply some styling to the paragraph
    const style = document.createElement('style');
    style.textContent = `
      p {
        color: blue;
      }
    `;
    
    // Append the elements to the shadow DOM
    shadowRoot.appendChild(style);
    shadowRoot.appendChild(paragraph);
  </script>
</body>
</html>


The text in the above code "This paragraph text is inside the Shadow DOM." will be displayed on the page, but its styling will be isolated from the rest of the document due to the use of Shadow DOM.


Imperative-only API for Shadow DOM:

As we observe closely in JavaScript, create Shadow DOM imperatively by selecting an element, attaching a shadow root (attachShadow({mode: 'open'})), and appending child elements.


const container = document.getElementById('parent');
const shadowRoot = container.attachShadow({ mode: 'open' });
const paragraph = document.createElement('p');
paragraph.textContent = 'This text is inside the Shadow DOM.';
const style = document.createElement('style');
style.textContent = 'p { color: blue; }';
shadowRoot.appendChild(style);
shadowRoot.appendChild(paragraph);This creates encapsulated DOM and styling within container, isolating the paragraph's appearance and behavior from the rest of the document.


We need a way to be able to serve shadow roots, of native and custom elements, in a static HTML document and let them upgrade progressively.

Declarative API for Shadow DOM:

In HTML, we can use the slot element to create a declarative API for Shadow DOM. This allows you to define placeholders for content insertion within custom elements.


Here's an example:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Declarative Shadow DOM</title>
</head>
<body>
  <div id="parent">
    <p>This content is outside the Shadow DOM.</p>
    <my-custom-element>
      <p slot="content">This text is inside the Shadow DOM.</p>
    </my-custom-element>
  </div>

  <script>
    customElements.define('my-custom-element', class extends HTMLElement {
      constructor() {
        super();
        const shadowRoot = this.attachShadow({ mode: 'open' });
        const template = document.querySelector('#my-custom-element-template');
        shadowRoot.appendChild(template.content.cloneNode(true));
      }
    });
  </script>

  <template id="my-custom-element-template">
    <style>
      p { color: blue; }
    </style>
    <slot name="content"></slot>
  </template>
</body>
</html>


In the declarative example, we use HTML to define a template for the Shadow DOM structure. We then use JavaScript to clone and append this template to the Shadow DOM, along with any additional content we wish to add. Declarative Shadow DOM removes this limitation, bringing Shadow DOM to the server.

Conclusion

Declarative Shadow DOM is a groundbreaking feature that enhances web components by allowing developers to define shadow DOM content directly within HTML. This approach simplifies the creation and maintenance of encapsulated components, improving code readability and reusability. For server-side rendering (SSR), Declarative Shadow DOM offers significant benefits by enabling better performance and SEO. By rendering shadow DOM content server-side, developers can ensure faster initial page loads and improved indexing by search engines. This innovation effectively bridges the gap between client-side encapsulation and server-side efficiency, making Declarative Shadow DOM a powerful tool for modern web development.