Shadow DOM in Web Component

Shadow DOM is a mechanism to encapsulate the DOM Tree. Shadow DOM is not a part of the main DOM tree. It prevents overriding the style or behavioral of the respective markup elements.

Following image describes the Shadow DOM from the main DOM tree.

Let’s assume, Document is the main root node of the main DOM tree.

Shadow Host is the link node between Shadow Tree and the main DOM tree. Shadow Tree is used to hidden DOM trees from the regular main DOM tree. Shadow Tree starts from Shadow Root(root node of the Shadow DOM tree) which is attached to Shadow Host.

Shadow Boundary is the boundary line where regular DOM tree begins and Shadow DOM Tree ends.

 

 

 

 

 

 

 

 

 

 

 

We can take the same example as described in previous session. Let’s first focus on the HTML file.
We have declared two header statements [Template in HTML 5, (learning web components)] with styleClass named “pageHeaderStyle“.

index.html | to build the customer registration page

<script src="index.js"></script>
<link rel="stylesheet" href="index.css"></link>
<body onload="loadTmplBody();"> 
<template id="tmplId" >
        <p class="pageHeaderStyle">Template in HTML 5</p>
        <p class="pageHeaderStyle">(learning web components)</p>
        <div id="firstdivId">
           <nice-form header="Customer Registration Form" subHeader="A unique venture company" id="niceformId">

           </nice-form>             
        </div> 
</template>
</body>

Now, we are trying to apply the style for styleClass named “pageHeaderStyle”.

index.css | to change the font color for the header contents

.pageHeaderStyle{
    color:red;
}

.pageHeaderStyle{
    color:green;
}

We have written same styleClass in CSS file. Let’s check what will be the result after execution of the HTML file?

We are keeping the same JS file.

index.js | to activate the template with custom element

function loadTmplBody(){   

    var tmpl = document.querySelector("#tmplId");
    tmpl.content.querySelector("#firstdivId").style = "width:100%; height:800px;background: linear-gradient(to bottom right, #ffffff 0%, #003366 100%);";
    var clonTmpl = tmpl.content.cloneNode(true); 
    document.body.appendChild(clonTmpl);

}
class NiceFormClass extends HTMLElement{
    constructor(){
        super();

        this.innerHTML = `<h1>${this.header}</h1>
                          <h3><i>(${this.subHeader})</i></h3>
                          <hr/>
                          <div style="border-style: solid;
                          border-width: 1px;
                          margin-left:3px;
                          border-color: black;background-color:#ccc; width:99.4%;height:200px;"></div>
                          <hr/>
                         `;

    }

    get header(){
        return this.getAttribute('header');
    }

    set header(val){
        this.setAttribute('header', val);
    }

    get subHeader(){
        return this.getAttribute('subHeader');
    }

    set subHeader(val){
        this.setAttribute('subHeader', val);
    }
    
}

customElements.define('nice-form', NiceFormClass);

Now, run the index.html file and you will get the color of both header contents [Template in HTML 5 and (learning web components)] have been overridden as green color, because, the styles are not encapsulated in the main DOM tree.

Result 1

How can we overcome this problem?
We can think about Shadow DOM. Now we will apply the Shadow DOM for this assignment.

We have modified the HTML to define the ids for one header content.

index.html | to apply the html id for the header content (learning lightning component)

<script src="index.js"></script>
<link rel="stylesheet" href="index.css"></link>
<body onload="loadTmplBody();"> 
<template id="tmplId" >
        <p class="pageHeaderStyle">Template in HTML 5</p>
        <p id="secondPgraphId">(learning web components)</p>
        <div id="firstdivId">
           <nice-form header="Customer Registration Form" subHeader="A unique venture company" id="niceformId">
		   </nice-form>             
        </div> 
</template>
</body>

We are keeping the same CSS file as described earlier. You can remove the duplicate pageHeaderStyle class from CSS file.

index.js | to apply the shadow DOM [Line no.8-13]

function loadTmplBody(){   

    var tmpl = document.querySelector("#tmplId");
    tmpl.content.querySelector("#firstdivId").style = "width:100%; height:800px;background: linear-gradient(to bottom right, #ffffff 0%, #003366 100%);";
    var clonTmpl = tmpl.content.cloneNode(true); 
    document.body.appendChild(clonTmpl);

    let host = document.querySelector('#secondPgraphId');
    let shadowRoot = host.createShadowRoot();
    let newP = document.createElement('p');
    newP.className="pageHeaderStyle1";
    newP.textContent="(learning web components)";
    shadowRoot.appendChild(newP);
}
class NiceFormClass extends HTMLElement{
    constructor(){
        super();

        this.innerHTML = `<h1>${this.header}</h1>
                          <h3><i>(${this.subHeader})</i></h3>
                          <hr/>
                          <div style="border-style: solid;
                          border-width: 1px;
                          margin-left:3px;
                          border-color: black;background-color:#ccc; width:99.4%;height:200px;"></div>
                          <hr/>
                         `;

    }

    get header(){
        return this.getAttribute('header');
    }

    set header(val){
        this.setAttribute('header', val);
    }

    get subHeader(){
        return this.getAttribute('subHeader');
    }

    set subHeader(val){
        this.setAttribute('subHeader', val);
    }
    
}

customElements.define('nice-form', NiceFormClass);

Following syntax has been used to apply Shadow DOM.

    let host = document.querySelector('#secondPgraphId');
    let shadowRoot = host.createShadowRoot();
    let newP = document.createElement('p');
    newP.className="pageHeaderStyle1";
    newP.textContent="(learning web components)";
    shadowRoot.appendChild(newP);

First, we got the DOM element for secondPgraphId by using querySelector and created Shadow Root for a particular Shadow Host. Then we have inserted new DOM into the Shadow DOM by declaration of document properties.

You can apply attachShadowRoot() instead of using createshadowRoot() function to apply Shadow DOM.

Result 2

You can see, now the style of second header content (learning web components) can not be changed due to the presence of Shadow DOM.

Now, if you do the inspect for a particular content in the browser, you can see the Shadow Root definition. Please see the following image.

 

15,837 total views, 3 views today

Rating: 5.0/5. From 4 votes.
Please wait...
This entry was posted in Lightning Web Component. Bookmark the permalink.

Leave a Reply