Web components are a relative new set of specifications which appeared at 2011 and aim for a better encapsulation and reusability of written components. These specifications consists of the Shadow DOM, Custom Elements, HTML Templates and Imports. Shadow DOM provides an API to work with an to the user hidden DOM tree, which enables the programmer to render his own elements like a native one. The Custom Elements specification defines the lifecycle a HTML element has, which is required to handle the element attributes and render the DOM of the custom element. There are two other specifications which describes how to import components into a document and how to define the component template. All of those play together to create super awesome web components
Here is a small example of a simple web component:
- <template>
- <span>Hello <span class="name"></span></span>
- </template>
- <script>
- const ownerDocument = (document._currentScript || document.currentScript).ownerDocument;
- const template = ownerDocument.querySelector('template').content;
- class HelloWorld extends HTMLElement {
- createdCallback() {
- const shadowRoot = this.createShadowRoot();
- shadowRoot.appendChild(document.importNode(template, true));
- this.nameHolder = shadowRoot.querySelector('.name');
- if (this.hasAttribute('name')) {
- this.renderName(this.getAttribute('name'));
- }
- }
- attributeChangedCallback(attribute, oldVal, newVal) {
- if (attribute === 'name') {
- this.renderName(newVal);
- }
- }
- renderName(name) {
- this.nameHolder.textContent = name;
- }
- }
- document.registerElement('hello-world', HelloWorld);
- </script>
And here is the usage of the component
So why is not everyone using these awesome techniques already?
-> Because of the crappy browser support -,-
If you want to support only the Google Chrome browser above version 35 you're lucky because the Google developers took care to implement even the first draft versions of the specification. Yay. So for Google Chrome everything is fine but the common websites got users with different browsers than chrome. So here are the bad news. The Mozilla developers took care to make Firefox over the last years at least as crappy as the Internet Explorer was and as well they decided to don't implement any of those new standards. So there is no support for Firefox in the latest version 53. Only the Android Internet browser and Opera supports the first draft of the specifications beside chrome.
Shadow DOM: http://caniuse.com/#search=shadow%20dom
Custom Elements: http://caniuse.com/#search=custom%20elements
HTML Imports: http://caniuse.com/#search=html%20imports
HTML Templates: http://caniuse.com/#search=html%20templates
So even if the specifications for the web components are not implemented in most of the browsers yet, you still can work with them by using polyfills. There is a polyfill for all of the web component specifications in version v0. But because it wraps all elements into a class to support the shadow dom, it slows down the browser tremendously and this sux. A new shadow dom and custom elements v1 polyfill, which was extracted from the new polymer 2.0 library, does this way better and faster but is not stable yet.
But still there are some subtleties you will recognize when you write web components. I will mention some I recognized:
- If you want to use custom font faces like for icon font's, you have to place the style definition before the component template because font faces are defined on the global scope and won't be recognized if they will be defined in the component scope.
- When you extend a native element like HTMLInputElement the resulting instance will have no getter or setter for the native attribute fields like "value" or "type".
- Calling element.cloneNode(true) will copy the DOM tree with all children but won't call it’s constructors and the custom elements never get initialized. Instead you should call document.importNode(element, true)
- Writing components with bigger templates and more interactions just sux because there will be so much redundant code of calling querySelector, binding events and manipulating the text content, classes or attributes.
At the end the technology is straight forward and a great idea but as usual not all browsers are ready yet.