Web Components

In this article by Arshak Khachatryan, the author of Getting Started with Polymer, we will discuss web components. Currently, web technologies are growing rapidly. Though most websites use these technologies nowadays, we come across many with a bad, unresponsive UI design and awful performance. The only reason we should think about a responsive website is that users are now moving to the mobile web. 55% of the web users use mobile phones because they are faster and more comfortable. This is why we need to provide mobile content in the simplest way possible. Everything is moving to minimalism, even the Web.

The new web standards are changing rapidly too. In this article, we will cover one of these new technologies, web components, and what they do.

We will discuss the following specifications of web components in this article:

  • Templates
  • Shadow DOM

(For more resources related to this topic, see here.)

Templates

In this section, we will discuss what we can do with templates. However, let's answer a few questions before this.

What are templates, and why should we use them?

Templates are basically fragments of HTML, but let's call these fragments as the "zombie" fragments of HTML as they are neither alive nor dead. What is meant by "neither alive nor dead"? Let me explain this with a real-life example.

Once, when I was working on the ucraft.me project (it's a website built with a lot of cool stuff in it), we faced some rather new challenges with the templates. We had a lot of form elements, but we didn't know where to save the form elements content. We didn't want to load the DOM of each form element, but what could we do? As always, we did some magic; we created a lot of div elements with the form elements and hid it with CSS. But the CSS display: none property did not render the element, but it loaded the element. This was also a problem because there were a lot of form element templates, and it affected the performance of the website.

I recommended to my team that they work with templates. Templates can contain HTML content, but they do not load the element nor render.

We call template elements "dead elements" because they do not load the content until you get their content with JavaScript. Let's move ahead, and let me show you some examples of how you can create templates and do some stuff with its content.

Imagine that you are working on a big project where you need to load some dynamic content without AJAX. If I had a task such as this, I would create a PHP file and get its content by calling the jQuery .load() function. However, now, you can save your content inside of the <template> element and get the content without any jQuery and AJAX but with a single line of JavaScript code. Let's create a template.

In index.html, we have <template> and some content we want to get in the future, as shown in the following code block:

<template class="superman">
  <div>
   <img src="assets/img/superman.png" class="animated_superman" />
  </div>
</template>

The time has now come for JavaScript! Execute the following code:

<script>
  // selecting the template element with querySelector()

  var tmpl = document.querySelector('.superman');
  //getting the <template> content
  var content = tmpl.content;
  // making some changes in the content
  content.querySelector('.animated_superman').width = 200;

  // appending the template to the body
  document.body.appendChild(content);
</script>

So, that's it! Cool, right? The content will load only after you append the content to the document. So, do you realize that templates are a part of the future web? If you are using Chrome Canary, just turn on the flags of experimental web platform features and enable HTML imports and experimental JavaScript.

There are four ways to use templates, which are:

  • Add templates with hidden elements in the document and just copy and paste the data when you need it, as follows:
    <div hidden data-template="superman">
      <div>
        <p>SuperMan Head</p>
        <img src="assets/img/superman.png" 
          class="animated_superman" />
      </div>
    </div>
    

    However, the problem is that a browser will load all the content. It means that the browser will load but not render images, video, audio, and so on.

  • Get the content of the template as a string (by requesting with AJAX or from <script type="x-template">).
  • However, we might have some problems in working with the string. This can be dangerous for XSS attacks; we just need to pay some more attention to this:
    <script data-template="batman" type="x-template">
      <div>
        <p>Batman Head this time!</p>
        <img src="assets/img/superman.png" 
          class="animated_superman" />
      </div>
    </div>
    
  • Compiled templates such as Hogan.js (http://twitter.github.io/hogan.js/) work with strings. So, they have the same flaw as the patterns of the second type.

Templates do not have these disadvantages. We will work with DOM and not with the strings. We will then decide when to run the code.

In conclusion:

  • The <template> tag is not intended to replace the system of standardization. There are no tricky iteration operators or data bindings.
  • Its main feature is to be able to insert "live" content along with scripts.
  • Lastly, it does not require any libraries.

Shadow DOM

The Shadow DOM specification is a separate standard. A part of it is used for standard DOM elements, but it is also used to create with web components. In this section, you will learn what Shadow DOM is and how to use it.

Shadow DOM is an internal DOM element that is separated from an external document. It can store your ID, styles, and so on. Most importantly, Shadow DOM is not visible outside of its scope without the use of special techniques. Hence, there are no conflicts with the external world; it's like an iframe.

Inside the browser

The Shadow DOM concept has been used for a long time inside browsers themselves. When the browser shows complex controls, such as a <input type = "range"> slider or a <input type = "date"> calendar within itself, it constructs them out of the most ordinary styled <div>, <span>, and other elements.

They are invisible at the first glance, but they can be easily seen if the checkbox in Chrome DevTools is set to display Shadow DOM:

Getting Started with Polymer

In the preceding code, #shadow-root is the Shadow DOM.

Getting items from the Shadow DOM can only be done using special JavaScript calls or selectors. They are not children but a more powerful separation of content from the parent.

In the preceding Shadow DOM, you can see a useful pseudo attribute. It is nonstandard and is present for solely historical reasons. It can be styled via CSS with the help of subelements—for example, let's change the form input dates to red via the following code:

<style>
  input::-webkit-datetime-edit {
    background: red;
  }
</style>

<input type="date" />

Once again, make a note of the pseudo custom attribute. Speaking chronologically, in the beginning, the browsers started to experiment with encapsulated DOM structure inside their scopes, then Shadow DOM appeared which allowed developers to do the same.

Now, let's work with the Shadow DOM from JavaScript or the standard Shadow DOM.

Creating a Shadow DOM

The Shadow DOM can create any element within the elem.createShadowRoot() call, as shown by the following code:

<div id="container">You know why?</div>

<script>
  var root = container.createShadowRoot();
  root.innerHTML = "Because I'm Batman!";
</script>

If you run this example, you will see that the contents of the #container element disappeared somewhere, and it only shows "Because I'm Batman!". This is because the element has a Shadow DOM and ignores the previous content of the element.

Because of the creation of Shadow DOM, instead of the content, the browser has shown only the Shadow DOM.

If you wish, you can put the contents of the ordinary inside this Shadow DOM. To do this, you need to specify where it is to be done. The Shadow DOM is done through the "insertion point", and it is declared using the <content> tag; here's an example:

<div id="container">You know why?</div>

<script>
  var root = container.createShadowRoot();
  root.innerHTML = '<h1><content></content></h1><p>Winter is 
    coming!</p>';
</script>

Now, you will see "You know why?" in the title followed by "Winter is coming!".

Here's a Shadow DOM example in Chrome DevTool:

Getting Started with Polymer

The following are some important details about the Shadow DOM:

  • The <content> tag affects only the display, and it does not move the nodes physically. As you can see in the preceding picture, the node "You know why?" remained inside the div#container. It can even be obtained using container.firstElementChild.
  • Inside the <content> tag, we have the content of the element itself. In this example string "You know why?".

With the select attribute of the <content> element, you can specify a particular selector content you want to transfer; for example, <content select="p"></content> will transfer only paragraphs.

Inside the Shadow DOM, you can use the <content> tag multiple times with different values of select, thus indicating where to place which part of the original content. However, it is impossible to duplicate nodes. If the node is shown in a <content> tag, then the next node will be missed.

For example, if there is a <content select="h3.title"> tag and then <content select= "h3">, the first <content> will show the headers <h3> with the class title, while the second will show all the others, except for the ones already shown.

In the preceding example from DevTools, the <content></content> tag is empty. If we add some content in the <content> tag, it will show that in that case, if there are no other nodes.

Check out the following code:

<div id="container">
  <h3>Once upon a time, in Westeros</h3>
  <strong>Ruled a king by name Joffrey and he's dead!</strong>
</div>

<script>
  var root = container.createShadowRoot();

  root.innerHTML = '<content select='h3'></content> \
  <content select=".writer"> Jon Snow </content> \
  <content></content>';
</script>

When you run the JS code, you will see the following:

  • The first <content select='h3'> tag will display the title
  • The second <content select = ".hero"> tag would show the hero name, but if there's no any element with this selector, it will take the default value: <content select=".hero">
  • The third <content> tag displays the rest of the original contents of the elements without the header <h3>, which it had launched earlier

Once again, note that <content> moves nodes on the DOM physically.

Root shadowRoot

After the creation of a root in the internal DOM, the tree will be available as container.shadowRoot.

It is a special object that supports the basic methods of CSS requests and is described in detail in ShadowRoot.

You need to go through container.shadowRoot if you need to work with content in the Shadow DOM. You can create a new Shadow DOM tree of JavaScript; here's an example:

<div id="container">Polycasts</div>

<script>
  // create a new Shadow DOM tree for element

  var root = container.createShadowRoot();

  root.innerHTML = '<h1><content></content></h1> <strong>Hey 
    googlers! Let\'s code today.</strong>';
</script>

<script>
  // read data from Shadow DOM for elem

  var root = container.shadowRoot;

  // Hey googlers! Let's code today.
  document.write('<br/><em>container: ' + root.
    querySelector('strong').innerHTML);
  // empty as physical nodes - is content
  document.write('<br/><em>content: ' + root.
    querySelector('content').innerHTML);
</script>

To finish up, Shadow DOM is a tool to create a separate DOM tree inside the cell, which is not visible from outside without using special techniques:

  • A lot of browser components with complex structures have Shadow DOM already.
  • You can create Shadow DOM inside every element by calling elem.createShadowRoot(). In the future, it will be available as a elem.shadowRoot root, and you can access it inside the Shadow DOM. It is not available for custom elements.
  • Once the Shadow DOM appears in the element, the content of it is hidden. You can see just the Shadow DOM.
  • The <content> element moves the contents of the original item in the Shadow DOM only visually. However, it remains in the same place in the DOM structure.

Detailed specifications are given at http://w3c.github.io/webcomponents/spec/shadow/.

Summary

Using web components, you can easily create your web application by splitting it into parts/components.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Getting Started with Polymer

Explore Title