Home Web Development Getting Started with Web Components

Getting Started with Web Components

By Prateek Jadhwani
books-svg-icon Book
eBook $15.99 $10.99
Print $21.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $15.99 $10.99
Print $21.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
About this book
Web Components are a set of APIs that help you build reusable UI modules that can operate in any modern browser using just Vanilla JavaScript. The power of Web Components lies in their ability to build frontend web applications with or without web frameworks. With this practical guide, you will understand how Web Components can help you build reusable UI components for your modern web apps. The book starts by explaining the fundamentals of Web Components' design and strategies for using them in your existing frontend web projects. You will also learn how to use JavaScript libraries such as Polymer.js and Stencil.js for building practical components. As you progress, you will build a single-page application using only Web Components to fully realize their potential. This practical guide demonstrates how to work with Shadow DOM and custom elements to build the standard components of a web application. Toward the end of the book, you will learn how to integrate Web Components with standard web frameworks to help you manage large-scale web applications. By the end of this book, you will have learned about the capabilities of Web Components in building custom elements and have the necessary skills for building a reusable UI for your web applications.
Publication date:
August 2019
Publisher
Packt
Pages
158
ISBN
9781838649234

 

Web Components Essentials and Specifications

Welcome to the world of Web Components.

Web Components, as the name indicates, are components that can be reused across different sections of a website by keeping encapsulation in check. They can even be published on the web, and be used by another site with the help of a simple import. This book covers all there is to know about Web Components. What they are made up of, how they can be used and in what scenarios. The book also covers wide variety of moderate and advanced level concepts such as good practices and integrating Web Components with other technologies.

In this chapter, we will talk about what Web Components are and how we can identify them while browsing various sites. We will also be talking about the specifications that make up Web Components along with detailed examples. You will be able to understand what custom elements are and how you can create one on your own. You will be able to encapsulate your Web Components with the help of a shadow DOM, and you will be able to use templates to achieve reusability.

While this chapter talks only about the basics of Web Components, by the end of this chapter you will be able to create your own Web Components from scratch, and understand the specifications associated with them.

In this chapter, we will cover the following topics:

  • Web Components
  • Web Component specifications
 

Technical requirements

In order to run the code, you will need a simple server, say a Python SimpleHTTPServer. In order to see the code on the browser, first start the server. On Mac, use the following command:

py -m SimpleHTTPServer 

On Windows, use the following command in the folder that you have the code :

py -m http.server

and then you can simply go to localhost:8080. It will run index.html for you in that folder.

 

Web Components

Let's say you have a phone with a touchscreen. This touchscreen is a component of the mobile phone, working in conjunction with various other components, such as the circuit board and battery. Very few of us know how a phone screen works individually, yet we're all able to operate a mobile phone with ease. The same can be said of Web Components, which are the complex building blocks of websites which become navigable to all.

More importantly, the millions of phone screens around the world today are largely based on only a handful of designs. Fundamentally, the technology behind the mobile component is reusable and adaptable, and the same principle applies to Web Components.

The above points show how component methodology can be useful in creating a better product. Now, you must be thinking, why do we even need to look into the concept of components on the web? Well, I would like you to recall the last five sites that you visited. All these five sites probably shared a few features in common. Some of these are a header, a footer, some sort of menu, and an advertisement section. All these features, in terms of functionality, are doing the same thing. The only thing that differs is the look and feel.

Let us consider another use case where the site domain is the same but there are multiple web apps running on that domain.

We have all used Google or at least two or three Google services. If we observe, there is a section at the top-right corner on any of the Google services/sites. It's your account information, the one with your profile picture. And it shows the list of accounts you have logged in with:

You will be able to see a similar account information card when you go from one service to another. Imagine being able to convert this functionality into an HTML tag <account-info> and being able to reuse it again and again on different services. This can be achieved with the help of Web Components. 

A Web Component is a collection of specifications that lets a user create a functionality with a certain look and feel and which can be reused in such a way that all this functionality is encapsulated. 

Just like the preceding example, <account-info>, a Web Component lets you put your functionality into its own custom name, which can be represented by an HTML tag, and then encapsulate its functionality. This encapsulation makes it easy to distribute and it can be reused again and again very easily.

In all, a Web Component lets you create a custom HTML tag that can be reused, and whose functionality is encapsulated from the user. 

Now that we know what Web Components are and what Web Components can do, let's talk about Web Component specifications.

 

Web Component specifications

Just like any technology, Web Components also have a set of specifications that need to be followed in order to achieve the functionality associated with them.

A Web Component specification has the following parts:

  • Custom element: The ability to create custom HTML tags and make sure that the browser understands how to use this HTML tag
  • Shadow DOM: The ability to encapsulate the contents of the component from other parts of the DOM
  • Template: Being able to create a reusable DOM structure that can be modified on the fly and output desired results

These three specifications, when used together, provide a way to create a custom HTML tag that can output desired results (DOM structure) and let it encapsulate from the page, making it reusable again and again.

Now that we know these specifications and what they do, let's dive into them individually and try to look at their JavaScript APIs.

Custom elements

A custom element specification lets you create a custom HTML tag that can be used as its own HTML tag on the page. In order to achieve this, we need to first write a class with the functionalities associated with that HTML element, and then we need to register it so that the browser understands what this HTML tag is, and how it can be used on the page. 

If you are someone who is new to the concept of classes in JavaScript, here is how you can create a class:

class myClass {
constructor() {
// do stuff
}
}

Pretty simple, right? Let's use the same class structure to create our custom element class, say HelloWorld:

class HelloWorld extends HTMLElement {
constructor() {
// very important
// needed in every constructor
// which extends another class
super();

// do magic here
this.innerText = 'Hello World';
}
}

In the preceding code, our custom element class is called HelloWorld and it is extending interface from the HTMLElement class, which represents how an HTML element should work on a page. So, HelloWorld now knows what click events are, what CSS is, and so on, simply by extending HTMLElement.

Inside this class, we have the constructor() method, which gets called as soon as a new instance of this class is created. The super() function needs to be called in order to correctly instantiate the properties of the extended class.

The preceding code simply creates the element class definition. We still need to register this element. We can do so by writing the following code:

customElements.define('hello-world', HelloWorld);

What it does is register the class HelloWorld by defining it using the define() interface in the customElements interface; hello-world is the name of the custom element that is going to be available on the page.

Once this is defined, you can used the custom element by simply writing the HTML tag as following:

<hello-world><hello-world>

When this code is run on a browser, it will render the text, Hello World.

Shadow DOM

This is the second specification for Web Components and this one is responsible for encapsulation. Both the CSS and DOM can be encapsulated so that they are hidden from the rest of the page. What a shadow DOM does is let you create a new root node, called shadow root, that is hidden from the normal DOM of the page.

However, even before we jump into the concept of a shadow DOM, let's try to look at what a normal DOM looks like. Any page with a DOM follows a tree structure. Here I have the DOM structure of a very simple page:

In the preceding image, you can see that #document is the root node for this page. 

You can find out the root node of a page by typing document.querySelector('html').getRootNode() in the browser console.

If you try to get the child nodes of an HTML tag using document.querySelector('html').childNodes in the browser console, then you can see the following screenshot:

This shows that the DOM follows a tree structure. You can go deeper into these nodes by clicking on the arrow right next to the name of the node. And just like how I have shown in the screenshot, anyone can go into a particular node by expanding it and change these values. In order to achieve this encapsulation, the concept of a shadow DOM was invented.

What a shadow DOM does is let you create a new root node, called shadow root, that is hidden from the normal DOM of the page. This shadow root can have any HTML inside and can work as any normal HTML DOM structure with events and CSS. But this shadow root can only be accessed by a shadow host attached to the DOM. 

For example, let's say that instead of having text inside the <p> tag in the preceding example, we have a shadow host that is attached to a shadow root. This is what the page source would look like:

Furthermore, if you tried to get the child nodes of this <p> tag, you would see something like this:

Notice that there is a <span> tag in the shadow root. Even though this <span> tag is present inside the <p> tag, the shadow root does not let JavaScript APIs touch it. This is how the shadow DOM encapsulates code inside itself.

Now that we know what a shadow DOM does, let's jump on to some code and learn how to create our own shadow DOMs.

Let's say we have a DOM with a class name entry. This is what it looks like:

<div class="entry"></div>

In order to create a shadow DOM in this div, we will first need to get the reference to this .entry div, then we need to mark it as a shadow root, and then append the content to this shadow root. So, here is the JavaScript code for creating a shadowRoot inside a div and adding contents to it:

// get the reference to the div
let shadowRootEl = document.querySelector('.entry');

// mark it as a shadow root
let shadowRoot = shadowRootEl.attachShadow({mode: 'open'});

// create a random span tag
// that can be appended to the shadow root
let childEl = document.createElement('span');
childEl.innerText = "Hello shadow DOM";

// append the span tag to shadow root
shadowRoot.appendChild(childEl);

Pretty simple, right? Remember, we are still discussing the shadow DOM spec. We haven't started implementing it inside a custom element yet. Let's recall the definition of our hello-world custom element. This is what it looked like:

class HelloWorld extends HTMLElement {
constructor() {
super();

// do magic here
this.innerText = 'Hello World';
}
}

customElements.define('hello-world', HelloWorld);

Notice that the text Hello World is currently being added to normal DOM. We can use the same shadow DOM concepts discussed earlier in this custom element.

First, we need to get the reference to the node where we want to attach the shadow root. In this case, let's make the custom element itself the shadow host by using the following code:

let shadowRoot = this.attachShadow({mode: 'open'});

Now, we can either add a text node or create a new element and append it to this shadowRoot:

// add a text node
shadowRoot.append('Hello World');

Templates

Till now, we have only created custom elements and shadow DOMs that require only one or, at the most, two lines of HTML code. If we move on to a real-life example, HTML code can be more than two lines. It can start from a few lines of nested div to images and paragraphs—you get the picture. The template specification provides a way to hold HTML on the browser without actually rendering it on the page. Let us look at a small example of a template:

<template id="my-template">
<div class="red-border">
<p>Hello Templates</p>
<p>This is a small template</p>
</div>
</template>

You can write a template inside <template> tags and assign it an identifier, just as I have done with the help of an id. You can put it anywhere on the page; it does not matter. We can get its content with the help of JavaScript APIs and then clone it and put it inside any DOM, just as I have shown in the following:

// Get the reference to the template
let templateReference = document.querySelector('#my-template');

// Get the content node
let templateContent = templateReference.content;

// clone the template content
// and append it to the target div
document.querySelector('#target')
.appendChild(templateContent.cloneNode(true));

Similarly, we can have any number of templates on the page, which can be used by any JavaScript code.

Let's now use the same template with a shadow DOM. We will keep the template as it is. The changes in the JavaScript code would be something like this:

// Get the reference to the template
let templateReference = document.querySelector('#my-template');

// Get the content node
let templateContent = templateReference.content;

// Get the reference to target DOM
let targetDOM = document.querySelector('#target');

// add a shadow root to the target reference DOM
let targetShadowRoot = targetDOM.attachShadow({mode: 'open'});

// clone the template content
// and append it to the target div
targetShadowRoot.appendChild(templateContent.cloneNode(true));

We are doing the same thing that we did in the previous example, but, instead of appending the code directly to the target div, we are first attaching a shadow root to the target div, and then appending the cloned template content.

We should be able to use the exact same concept inside the autonomous custom element that uses a shadow DOM. Let's give it a try.

Let's edit the id of the template and call it hello-world-template:

<template id="hello-world-template">
<div>
<p>Hello Templates</p>
<p>This is a small template</p>
</div>
</template>

We will follow the exact same approach that we followed in the preceding example. We will get the template content from the template reference, clone it, and append it in the custom element, making the code of the custom element look like the following:

class HelloWorld extends HTMLElement {
constructor() {
super();

// Get the reference to the template
let templateReference = document.querySelector('#hello-world-template');

// Get the content node
let templateContent = templateReference.content;

let shadowRoot = this.attachShadow({mode: 'open'});

// add a text node
shadowRoot.append(templateContent.cloneNode(true));
}
}

customElements.define('hello-world', HelloWorld);

Now we can simply call the HTML tag inside our page using the following code:

<hello-world></hello-world>

If we inspect the DOM structure inside developer tools, this is what we see:

Module loader API

Module loader API is not a part of Web Component spec sheet, but it is definitely something that is useful to know when it comes to creating and using multiple classes. As the name says, this specification lets a user load the modules. That is, if you have a bunch of classes, you can use module loaders to load these classes into the web page.

If your build process involves using WebPack or Gulp or anything else that lets you import modules directly or indirectly, please feel free to skip this section.

Let's start with the basics. Let's say we have our index.html like this:

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
</head>
<body>
<p>Placeholder for Random Number</p>
</body>
</html>

We can see that there is a <p> tag in this HTML file. Now, let's say we have a class called AddNumber, whose purpose is to add a random number between 0 and 1 to this <p> tag. This would make the code look something like this:

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
</head>
<body>
<p>Placeholder for Random Number</p>

<script type="text/javascript">
class AddNumber {
constructor() {
document.querySelector('p').innerText = Math.random();
}
}

new AddNumber();
</script>

</body>
</html>

Simple, right? If you open the page on a browser, you will simply see a random number, and if you inspect the page, you will see that the random number replaced the text which was inside the <p> tag.

If we choose to store it in a JavaScript file, we can try to import it using the following code, where addNumber.js is the name of the file:

<script type="text/javascript" src="./addNumber.js"></script>

Now, let's say you have a randomNumberGenerator function instead of the Math.random() method. The code would look something like this:

class AddNumber {
constructor() {
// let's set the inner text of
// this element to a smiley
document.querySelector('p').innerText = randomNumberGenerator();
}
}
function randomNumberGenerator() {
return Math.random();
}
new AddNumber();

We also want the ability to let the user create a new object of the AddNumber class, rather than us creating it in the file. We do not want the user to know how randomNumberGenerator works, so we want the user to be only able to create the object of AddNumber. This way, we reach how modules work. We, the creators of modules, decide which functionalities the user can use and which they cannot.

We can choose what the user can use with the help of the export keyword. This would make the code look something like this:

//addNumber.js

export default class AddNumber {
constructor() {
document.querySelector('p').innerText = randomNumberGenerator();
}
}

function randomNumberGenerator() {
return Math.random();
}

When this file is imported (note that we haven't talked about imports yet), the user will only be able to use the AddNumber class. The randomNumberGenerator function won't be available to the user.

Similarly, if you have another file with, say, two other functions, add() and subtract(), you can export both of them as shown in the following:

// calc.js

export function add(x, y) {
return x + y;
}

export function subtract(x, y) {
return x - y;
}

Importing a module can be easily done with the help of the import keyword. In this section, we will talk about the type="module" attribute.

Inside the HTML file, index.html, instead of type=text/javascript, we can use type=module to tell the browser that the file that we are importing is a module. This is what it will look like when we are trying to import the file addNumber.js:

<script type="module" >
import AddNumberWithNewName from './addNumber.js';
new AddNumberWithNewName();
</script>

This is how it will look if we import functions from the calc.js module:

<script type="module" >
import {add, subtract} from './calc.js';
console.log(add(1,5));
</script>

Notice how we can change the name of the module exported from AddNumber, which uses export default, and how we have to use the same name as the name of the function exported using export.

Named export versus default export

In the previous examples, that is, addNumber.js and calc.js, we saw that there are two ways to export something: export and export default. The simplest way to understand it is as follows: when a file exports multiple things with different names and when these names cannot be changed after import, it is a named export, whereas, when we export only one thing from a module file and this name can be changed to anything after the import, it is a default export. 

Custom elements using imports

Let's say we need to create a Web Component that does a very simple task of showing a heading and a paragraph inside it, and the name of the custom element should be <revamped-paragraph>. This is what the definition of this Web Component would look like:

//revampedParagraph.js

export default class RevampedParagraph extends HTMLElement {
constructor() {
super();

// template ref and content
let templateReference = document.querySelector('#revamped-paragraph-template');
let template = templateReference.content;

// adding html from template
this.append(template.cloneNode(true));
}
}

Our index.html file, the file that imports this module, would look like this:

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<title>Revamped Paragraph</title>

<!--
Notice how we use type="module"
-->
<script type="module">

// imports object from the module
// and names it as RevampedParagraph
// You can name it anything you want
// since it is a default export
import RevampedParagraph from './revampedParagraph.js';

// We are now defining the custom element
customElements.define('revamped-paragraph', RevampedParagraph);
</script>

</head>
<body>

<revamped-paragraph></revamped-paragraph>

<!--
Template for
Revamped Paragraph
-->
<template id="revamped-paragraph-template">
<h1>Revamped Paragraph</h1>
<p>This is the default paragraph inside
the revamped-paragraph element</p>
</template>

</body>
</html>

Notice how the template is a part of our HTML, and how it gets used when the module is imported. We will be learning about all the steps that take place from the actual registration of the Web Components to what happens when they are removed from the page in the next chapter, where we will learn about life cycle methods. But for now, we need to look at more examples to understand how to create Web Components.

Let's take a look at another example. In this example, we need to import multiple Web Components in the index.html file. The components are as follows:

  • A student attendance table component: A table that shows the index number, student name, and attendance in a checkbox. This data is obtained from a student.json file.
  • An information banner component: The purpose of this component is to show a phone number and an address for the school where these students are studying.
  • A time slot component: A component that lets the user select a time slot for the class between three sets of timings.

Let us start with the first one, the <student-attendance-table> component. We need to first identify what it needs. In my opinion, these are the things it needs:

  • A fetch call to the student.json file
  • A template for each row of the string. I will be using template strings here
  • A default text that says loading... when it is making the call and another text that says unable to retrieve student list. when the fetch call fails

This is what our student.json file looks like:

[
{
"name": "Robert De Niro",
"lastScore": 75
},
{
"name": "Jack Nicholson",
"lastScore": 87
},
{
"name": "Marlon Brando",
"lastScore": 81
},
{
"name": "Tom Hanks",
"lastScore": 62
},
{
"name": "Leonardo DiCaprio",
"lastScore": 92
}
]

This is what the definition of the Web Component looks like:

// StudentAttendanceTable.js

export default class StudentAttendanceTable extends HTMLElement {
constructor() {
super();

// we simply called another method
// inside the class
this.render();
}

render() {
// let put our loading text first
this.innerText = this.getLoadingText();

// let's start our fetch call
this.getStudentList();
}

getStudentList() {
// lets use fetch api
// https://developer.mozilla.org/en-US/docs/Web
// /API/Fetch_API/Using_Fetch
fetch('./student.json')
.then(response => {

// converts response to json
return response.json();

})
.then(jsonData => {
this.generateTable(jsonData);
})
.catch(e => {

// lets set the error message for
// the user
this.innerText = this.getErrorText();

// lets print out the error
// message for the devs
console.log(e);
});

}

generateTable(names) {
// lets loop through names
// with the help of map
let rows = names.map((data, index) => {
return this.getTableRow(index, data.name);
});

// creating the table
let table = document.createElement('table');
table.innerHTML = rows.join('');

// setting the table as html for this component
this.appendHTMLToShadowDOM(table);
}

getTableRow(index, name) {
let tableRow = `<tr>
<td>${index + 1}</td>
<td>${name}</td>
<td>
<input type="checkbox" name="${index}-attendance"/>
</td>
</tr>`;

return tableRow;
}

appendHTMLToShadowDOM(html) {
// clearing out old html
this.innerHTML = '';

let shadowRoot = this.attachShadow({mode: 'open'});

// add a text node
shadowRoot.append(html);
}

getLoadingText() {
return `loading..`;
}

getErrorText() {
return `unable to retrieve student list.`;
}
}

Notice the functions getLoadingText() and getErrorText(). Their purpose is simply to return a text. Then the render() method first consumes the getLoadingText() method, and then makes the call using getStudentList() to fetch the student list from student.json file.

Once this student list is fetched, it gets passed onto generateTable() method, where every name and its index is passed into the getTableRow() method to generate rows and then gets returned back to be a part of the table. Once the table is formed, it is then passed into the appendHTMLToShadowDOM() method to be added to the shadow DOM for the component.

It's time to look into the <information-banner> component. Since this component simply needs to display a phone number and an address of the school where they are studying, we can use <template> and make it work. This is what it looks like:

//InformationBanner.js

export default class InformationBanner extends HTMLElement {
constructor() {
super();

// we simply called another method
// inside the class
this.render();
}

render() {

// Get the reference to the template
let templateReference = document.querySelector('#information-banner-template');

// Get the content node
let templateContent = templateReference.content;

let shadowRoot = this.attachShadow({mode: 'open'});

// add the template text to the shadow root
shadowRoot.append(templateContent.cloneNode(true));
}
}

Furthermore, information-banner-template looks something like this:

<template id="information-banner-template">
<div>
<a href="tel:1234567890">Call: 1234567890</a>
<div>
<p>Just Some Random Street</p>
<p>Town</p>
<p>State - 123456</p>
</div>
</div>
</template>

As you can see, it is not much different than the custom elements we have already talked about in previous sections.

Let's move on to the last custom element, the <time-slot> component. Since it also involves a preset number of time slots, we can use a <template> tag to do our work. 

The template would look something like this:

<template id="time-slot-template">
<div>
<div>
<input type="radio" name="timeslot" value="slot1" checked> 9:00
AM - 11:00 AM
</div>
<div>
<input type="radio" name="timeslot" value="slot2"> 11:00 AM -
1:00 PM
</div>
<div>
<input type="radio" name="timeslot" value="slot3"> 1:00 PM - 3:00
PM
</div>
</div>
</template>

The definition of the <time-slot> component would look like this:

// TimeSlot.js

export default class TimeSlot extends HTMLElement {
constructor() {
super();

// we simply called another method
// inside the class
this.render();
}

render() {

// Get the reference to the template
let templateReference = document.querySelector('#time-slot-
template');

// Get the content node
let templateContent = templateReference.content;

let shadowRoot = this.attachShadow({mode: 'open'});

// add the template text to the shadow root
shadowRoot.append(templateContent.cloneNode(true));
}
}

It is the same as the previous component.

Now that we have written the Web Components, it's time to take a look at the index.html file that includes all of these components together. This is what it looks like:

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<title>Student Page</title>

<!--
Notice how we use type="module"
-->
<script type="module">

// importing the first custom element
import StudentAttendanceTable from './StudentAttendanceTable.js';

// importing the second custom element
import InformationBanner from './InformationBanner.js';

// importing the third custom element
import TimeSlot from './TimeSlot.js';

customElements.define('student-attendance-table',
StudentAttendanceTable);
customElements.define('information-banner', InformationBanner);
customElements.define('time-slot', TimeSlot);
</script>

</head>
<body>

<time-slot></time-slot>
<student-attendance-table></student-attendance-table>
<information-banner></information-banner>

<template id="information-banner-template">
<div>
<a href="tel:1234567890">Call: 1234567890</a>
<div>
<p>Just Some Random Street</p>
<p>Town</p>
<p>State - 123456</p>
</div>
</div>
</template>

<template id="time-slot-template">
<div>
<div>
<input type="radio" name="timeslot" value="slot1" checked>
9:00 AM - 11:00 AM
</div>
<div>
<input type="radio" name="timeslot" value="slot2"> 11:00 AM -
1:00 PM
</div>
<div>
<input type="radio" name="timeslot" value="slot3"> 1:00 PM -
3:00 PM
</div>
</div>
</template>

</body>
</html>

As you can see, one <script> tag of type="module" can import all three of them together, and can register the custom elements, which can be used in the <body> tag.

 

Summary

In this chapter, we talked about Web Components and how we are able to identify them in our daily web visits. We also talked about the specifications associated with Web Components, making it easier to understand even further. We looked into custom elements and how we can create our own custom elements. We talked about the shadow DOM and how it provides a level of encapsulation for our Web Components. We then talked about templates and how they provide an element of reusability inside a Web Component. We also looked into modules and how they let you create and add Web Components dynamically. 

We dived deep into creating a Web Component with detailed code examples. With this, we should be able to create a simple Web Component from scratch without any issues.

In the next chapter, we will look into how we can make our Web Components do more with life cycle methods.

About the Author
  • Prateek Jadhwani

    Prateek Jadhwani is a developer specializing in frontend technologies, living and working in the US. His experience includes 10 years of working as a frontend developer for many high-profile clients and many early-adoption side projects. Prateek had his first exposure to Web Components in 2014, and instantly fell in love with component-driven methodologies. Since then, he has evangelized Web Components and its related libraries to people at work and outside of work. Prateek loves all things open source and enjoys writing good JavaScript. A love for programming in general and a thirst for knowledge provide the motivation he carries through his work.

    Browse publications by this author
Getting Started with Web Components
Unlock this book and the full library FREE for 7 days
Start now