DEV Community

Priya Seo
Priya Seo

Posted on • Edited on

GETTING FAMILIAR WITH HTML5 WEB COMPONENT

 Web Component is a feature that is being incorporated in HTML5 DOM Specifications by W3C.

Web Components are a set of APIs’ that allow you to create new custom, reusable, encapsulated HTML tags to use in web apps. Custom Components and widgets build on the web Component standard, will work across modern browsers, and can be used with any JavaScript library or framework that works with HTML.

Web Components are based on existing web standards. Feature to Support web Components are currently being added to the HTML and DOM specs, letting web developers easily extends HTML with new elements with encapsulated styling and custom behaviour.

Web Component building blocks:

1.Custom Elements: 

Custom elements API provides developer with the ability to create fully featured standalone DOM elements having their own behaviour and CSS styling. Below is one such example. Where we create an Element showing Movies And its Description  

  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  6. <meta http-equip="X-UA-Compatible" content="ie=edge">  
  7. <title>Template Demo</title>  
  8. </head>  
  9. <body>  
  10. Hello World  
  11.   
  12. <template id="tmpTopMovies">  
  13. <h3> Movie Name </h3>  
  14. <p> Desc </p>  
  15. </template>  
  16.   
  17. <div id="tmpPlaceholder"></div>  
  18.   
  19. <script>  
  20.   
  21. let movies = [  
  22. {name : "Lord of Rings", detail : "Some info about Lord of Rings"},  
  23. {name : "Star Wars", detail : "Some info about Star Wars"},  
  24. ];  
  25.   
  26. let t = document.querySelector('#tmpTopMovies');   
  27. let pholder = document.querySelector('#tmpPlaceholder');   
  28.   
  29. for(i in movies)
  30. {  
  31. t.content.querySelector('h3').innerText = movies[i].name;  
  32. t.content.querySelector('p').innerText = movies[i].detail;  
  33. let clone = document.importNode(t.content,true);  
  34. pholder.appendChild(clone);  
  35. }  
  36. </script>  
  37. </body>  
  38. </html> 

In the Above Example there is a template containing Movies Name and Description of the movie. And It is handled by JavaScript. In JS there is an array containing name and details. And adding these array-element to template.

  1. Shadow DOM.

A shadow tree is a node tree whose root is a shadow root. Shadow DOM provides style and mark-up encapsulation. To create shadow DOM, select an element and call its createShadowRoot method which returns a fragment to which you can append content. This fragment returned is called as Shadow Root. The shadow root and its children are not visible to the user, but browser renders them when it encounters our tag. It allows to isolate DOM of our component and scope and simplify CSS.

  1. <style>  
  2.   /* document style won't apply to the shadow tree inside #elem (1) */  
  3.   p { color: red; }  
  4. </style>  
  5.   
  6. <div id="elem"></div>  
  7.   
  8. <script>  
  9.   elem.attachShadow({mode: 'open'});  
  10.     // shadow tree has its own style (2)  
  11.   elem.shadowRoot.innerHTML = `  
  12.     <style> p { font-weight: bold; } </style>  
  13.     <p>Hello, John!</p>  
  14.   `;  
  15.   
  16. //<p> is only visible from queries inside the shadow tree (3)  
  17.   alert(document.querySelectorAll('p').length); // 0  
  18.   alert(elem.shadowRoot.querySelectorAll('p').length);// 1  
  19. </script> 

Description: 

Shadow DOM is a way to create a component-local DOM.

shadowRoot = elem.attachShadow({mode: open|closed}) – creates shadow DOM for elem. If mode="open", then it’s accessible as elem.shadowRoot property.

We can populate shadowRoot using innerHTML or other DOM methods.

  1. HTML Templates:

It defines a new <template> element, which creates chunks of HTML. Templates allow declaration of mark-up fragments which are parsed by the browser as HTML and are not interpreted at page load time but can be used at a later stage. These templates can be instantiated, cloned and reused. Everything inside a <template> tag is considered as inert by the browser.

  1. <template>  
  2.     <p>Hello There.</p>  
  3.     <p>I m a template</p>  
  4. </template>  
  1. HTML Imports:

Using HTML templates, you can define templates. But what if the HTML mark-up is quite large, your HTML file will look shabby. Won’t it be good if we can keep our template in a separate file? HTML import is here to our rescue. HTML imports allow to import templates from different HTML files. You can organize your templates in different files and then import them as below: -

  1. <link rel="import" href="mydocument.html">  

Example: 

Below is an example of an Image Slider Web Component that changes the image after every 1500ms and updated the image title.

HTML:

  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  6. <meta http-equip="X-UA-Compatible" content="ie=edge">  
  7. <title>Template Demo</title>  
  8. </head>  
  9. <body>  
  10. Image Slide  
  11.   
  12. <template id="image-slider-template">  
  13. <div class="image-container">  
  14. <h4 class="image-title"></h4>  
  15. </div>  
  16. </template>  
  17.   
  18. <image-slider   
  19. data-images="https://pluralsight.imgix.net/paths/path-icons/nodejs-601628d09d.png,https://camo.githubusercontent.com/eb464a60a4a47f8b600aa71bfbc6aff3fe5c5392/68747470733a2f2f7261772e6769746875622e636f6d2f766f6f646f6f74696b69676f642f6c6f676f2e6a732f6d61737465722f6a732e706e67,https://camo.githubusercontent.com/891e94cd8dda7f40f451bb27067be513c230318a/68747470733a2f2f7261772e6769746875622e636f6d2f766f6f646f6f74696b69676f642f6c6f676f2e6a732f6d61737465722f626f676a732f6a732e706e67" >  
  20. </image-slider>  
  21. </body>  
  22. </html>  

JavaScript:

  1. <script>
  2. class ImageSlider extends HTMLElement {  
  3.   constructor() {  
  4.    // If you define a constructor, always call super() first as it is required by the CE spec.  
  5.     super();  
  6.   }  
  7.   
  8.   connectedCallback() {  
  9.     debugger;  
  10.     const shadowRoot = this.attachShadow({ mode: "open" });  
  11.     const template = document.querySelector("#image-slider-template");  
  12.     const instance = template.content.cloneNode(true);  
  13.     shadowRoot.appendChild(instance);  
  14.   
  15.     this.images = this.getAttribute("data-images").split(",");  
  16.   
  17.     let imageContainer = this.shadowRoot.querySelector(".image-container");  
  18.     imageContainer.style.height = '200px';  
  19.     imageContainer.style.width = '200px';  
  20.     imageContainer.style.backgroundSize = "contain"  
  21.     imageContainer.style.backgroundImage =  
  22.   
  23.       "url(" + this.images[0] + ")";  
  24.   
  25.     this.shadowRoot.querySelector(".image-title").innerHTML = "Image " + 1;  
  26.     this.toggleImage();  
  27.   
  28.  }  
  29.    
  30.   toggleImage() {  
  31.   
  32.     let currentImage = 1;  
  33.     let images = this.images;  
  34.     let shadowRoot  = this.shadowRoot;  
  35.   
  36.     setInterval(function() {  
  37.   
  38.       if (currentImage > images.length)  
  39.       {  
  40.        currentImage = 1;  
  41.      }  
  42.   
  43.       debugger;  
  44.   
  45.       shadowRoot.querySelector(".image-container").style.backgroundImage =  
  46.   
  47.         'url(' + images[currentImage - 1] + ')';  
  48.   
  49.       shadowRoot.querySelector(".image-title").innerHTML =  
  50.   
  51.         "Image " + currentImage;  
  52.   
  53.       currentImage++;  
  54.   
  55.     }, 1500);  
  56.   }  
  57. }  
  58.   
  59. customElements.define("image-slider", ImageSlider);  
  60. </script>

Now that we know which specifications web components leverage, let's look at a custom element's lifecycle. I know, I know, we'll get to the code soon!

  A component's lifecycle:

  1. class MyElement extends HTMLElement {  
  2.     constructor() {  
  3.         // always call super() first  
  4.         super();   
  5.         console.log('constructed!');  
  6.     }  
  7.   
  8.      connectedCallback() {  
  9.         console.log('connected!');  
  10.     }  
  11.   
  12. disconnectedCallback() {  
  13.         console.log('disconnected!');  
  14.     }  
  15.   
  16.  attributeChangedCallback(name, oldVal, newVal) {  
  17.         console.log(`Attribute: ${name} changed!`);  
  18.     }  
  19.   
  20.  adoptedCallback() {  
  21.         console.log('adopted!');  
  22.     }  

Following are the methods of a component life cycle:

  • constructor():

The constructor runs whenever an element is created, but before the element is attached to the document. We'll use the constructor for setting some initial state, event listeners, and creating the shadow DOM.

  • connectedCallback():

The connectedCallback is called when the element is inserted to the DOM. It's a good place to run setup code, like fetching data, or setting default attributes.

  • disconnectedCallback() :

The disconnectedCallback is called whenever the element is removed from the DOM. Clean up time! We can use the disconnectedCallback to remove any event listeners or cancel intervals.

  • attributeChangedCallback(name, oldValue, newValue) :

The attributeChangedCallback is called any time your element's observed attributes change. We can observe an element's attributes by implementing a static observedAttributes getter.

  • adoptedCallback():

The adoptedCallback is called each time the custom element is moved to a new document. You'll only run into this use case when you have <iframe> elements in your page.



Top comments (0)