I. What?
Web Components are a new browser feature that provides a standard component model for the Web, consisting of several pieces: Shadow DOM, Custom Elements, HTML Imports and HTML Templates.
(Extracted from w3c/webcomponents)
That is to say, Web Components is a Web component model standard, provided by browsers with native feature support, including Shadow DOM, Custom Elements, HTML Imports and HTML Templates
Specification Status
The 4 dependencies, current status (2017/12/1) is as follows:
Completed Work
2014-03-18 HTML Templates Group Note
Drafts
2017-09-05 Shadow DOM Working Draft
2016-10-13 Custom Elements Working Draft
2016-02-25 HTML Imports Working Draft
Obsolete
2014-07-24 Introduction to Web Components Retired
(Extracted from All Standards and Drafts - W3C)
So, these 4 dependencies currently only 1 is completed (HTML Templates), and hasn't become a recommended standard yet (just NOTE, didn't become REC). The other 3 are still in Working Draft (WD) status
P.S. For more information about W3C document status like REC, NOTE, etc., please check [W3C Specification Development Process](/articles/w3c 规范制定流程/)
And Web Components specification itself had a version in 2014 (Introduction to Web Components), was retired, currently Web Components is in no specification status, github seems still active
P.S. If really curious, can take a look at the retired version
Implementation Status
Although specification is still in unclear status, but some browsers have provided varying degrees of support for Web Components dependent features:
Shadow DOM
v0 Chrome25+ Firefox X Safari X Opera15+ Android4.4+ IOS Safari X
v1 Chrome53+ Firefox X Safari 10+ Opera40+ Android5+ IOS Safari 10.2+
Custom Elements
v0 Chrome33+ Firefox X Safari X Opera20+ Android4.4.4+ IOS Safari X
v1 Chrome54+ Firefox X Safari 10.1+ Opera41+ Android5+ IOS Safari 10.3
HTML Imports
Chrome36+ Firefox X Safari X Opera23+ Android5+ IOS Safari X
HTML Templates
Chrome26+ Firefox 22 Safari 7.1 Opera15+ Android4.4+ IOS Safari 8
Note: Android5+ refers to Android5-6.x WebView: Chromium 62, and doesn't distinguish partial support and full support
Chrome, Opera green all the way, Safari and mobile roughly keeping up, Firefox just passing through. But from current compatibility situation, PC and mobile are both unusable
P.S. For more information about compatibility, please check Can I use... Support tables for HTML5, CSS3, etc
Additionally, there are polyfills and component libraries to play with:
-
Polymer 2.0: Google
-
X-Tag: Microsoft
Function
Web Components hopes to provide standardized component definition method, promote Web component standardization
Let browsers support environmental features needed for componentization solutions, including Shadow DOM, Custom Elements, HTML Imports and Templates
So first let's see what these dependent features can do:
-
Shadow DOM: Sandbox environment, used for component isolation. Components are not affected by external, components also don't affect each other
-
Custom Elements: Component reference method. Reference components in the form of custom elements
-
HTML Imports and Templates: Component resource loading method and component declaration method. Component declaration is placed in
<template>tag, load component resources through<link rel="import" href>
We discover the core is component encapsulation, hide component details through Shadow DOM, effect similar to:
<video src="./video.mp4" controls></video>
HTML page containing this snippet will present a fully functional video player, with play button, progress bar, volume control button, etc.
Web Components usage is similar to this:
<my-app>
<my-nav-bar>
<my-title>Order Center</my-title>
</my-nav-bar>
<my-aside-menu/>
<my-filter-panel/>
<my-order-list/>
</my-app>
Package view structure and styles into custom HTML elements, reference in black-box component form. Component is defined in isolated environment (Shadow DOM), HTML, CSS, Script are all safe, external cannot directly change component's internal logic/view state
Of course, besides encapsulation, components at least also lack:
-
Combination method, such as through Shadow DOM's
<slot> -
Communication mechanism, such as through attributeChangedCallback and other lifecycle Hooks
This part of content should be defined in Web Components' own specification (such as the previously retired Introduction), as for higher-level things, they're not within Web Components' consideration scope, after all the first step of component standardization should be from nothing to something
II. Starting from video
Just write one line of video tag:
<video src="./foo.webm" controls></video>
Page can present a fully functional video player, where are the structure definitions and style declarations for play button, progress bar hidden? Could it be like radio buttons and other form elements, rendered by system platform controls? If so, then what about platform-independent parts, such as textbox's placeholder, how is it implemented?
Actually, textbox's placeholder is similar to video, some visible but (in structured document) unfindable elements are all hidden in Shadow DOM:

video, input are equivalent to browser's built-in components, component view structure and default styles are hidden in Shadow DOM, component logic is completely hidden, only exposing autoplay, oninput and other state/behavior Hooks to communicate with external
At this point, we discover it's very similar to Web Components concept, so-called Web Components is nothing more than exposing browser's component mechanism, for Web developers to use, this way we can also happily define "native controls" (components)
III. Shadow DOM
Previously always emphasized hiding things in Shadow DOM, because Shadow DOM's function is equivalent to sandbox, provides component isolation environment
Can play with this feature in Chrome:

After opening Shadow DOM display switch, let's take a look at textbox's hidden part:
<input class="nav-search column-07 start-18" name="s" type="text" placeholder="Hmm. I've seen your little bear.">
#shadow-root (user-agent)
<div pseudo="-webkit-input-placeholder" id="placeholder" style="display: block !important; text-overflow: clip;">Hmm. I've seen your little bear.</div>
<div id="inner-editor"></div>
placeholder quietly stays here, #inner-editor is used to display input text
Using Shadow DOM feature provided by browser, we can create our own Shadow Root:
document.body.innerHTML = '<div class="container"></div>';
var host = document.querySelector('.container');
var root = host.createShadowRoot();
root.innerHTML = '<p>How <em>you</em> doin?</p>'
At this point node structure is like this:
<div class="container"></div>
#shadow-root (open)
<p>How <em>you</em> doin?</p>
Page displays "How you doin?", because content under Shadow Root will be presented on page
Shadow Root refers to Fragment returned by createShadowRoot():
host.createShadowRoot() instanceof DocumentFragment === true
Can do DOM operations on Fragment, equivalent to an independent HTML parsing environment, not interfered by external
Additionally there are 2 concepts: Shadow Host and Shadow Boundary
Shadow Host
Shadow Root's "host", connection point between Shadow DOM and DOM, plainly speaking it's where Shadow DOM hangs (the host in above example)
Since there's hosting relationship, let's try:
host.parentElement.removeChild(host)
Find nothing left in body, Shadow DOM is taken down along with host (return value is游离的 div node, at this time Shadow DOM still hangs on div, can append node back to verify)
Shadow Boundary
An abstract concept, refers to the "barrier" layer outside Shadow DOM, it can isolate HTML and CSS under Shadow Root, mutually unaffected with styles in document where Shadow Host is located, and external cannot get node objects under Shadow Root through JS, similar to iframe's isolation effect
This is exactly what Web development has always wanted for module isolation, although can be filled through namespace and other engineering solutions, but there are always some defects that cannot be remedied, fundamental reason is HTML and CSS finally presented on page have no scope concept, restriction means in development stage all become moral constraints here. On the other hand, constraining with engineering means, there may also be problems of too many restrictions causing business to be tied up
Insertion Points
Additionally, it's also necessary to know basic support for component composition:
<div class="breaking">
<ul>
<slot name="breaking"></slot> <!-- slot for breaking news -->
</ul>
</div>
<div class="other">
<ul>
<slot></slot> <!-- slot for the rest of the news -->
</ul>
</div>
(Extracted from Shadow DOM W3C Editor's Draft 14 November 2017)
Two insertion methods, respectively representing named slot and default slot, looks very familiar, Vue templates are written this way, because:
For example, Vue components implement the Slot API and the is special attribute.
As for relationship between Vue and Web Components, we'll talk about it later
IV. Custom Elements
Create custom elements, icing on the cake small thing. Without custom element feature, we need to do this:
<ul class="stories">
<li><a href="//example.com/stories/1">A story</a></li>
<li><a href="//example.com/stories/2">Another story</a></li>
<li class="breaking" slot="breaking"><a href="//example.com/stories/3">Also a story</a></li>
<li><a href="//example.com/stories/4">Yet another story</a></li>
<li><a href="//example.com/stories/5">Awesome story</a></li>
<li class="breaking" slot="breaking"><a href="//example.com/stories/6">Horrible story</a></li>
</ul>
With it, write like this:
<stories>
<li><a href="//example.com/stories/1">A story</a></li>
<li><a href="//example.com/stories/2">Another story</a></li>
<breaking slot="breaking"><a href="//example.com/stories/3">Also a story</a></breaking>
<li><a href="//example.com/stories/4">Yet another story</a></li>
<li><a href="//example.com/stories/5">Awesome story</a></li>
<breaking slot="breaking"><a href="//example.com/stories/6">Horrible story</a></breaking>
</stories>
From semantics perspective, custom elements have stronger expressiveness, and more concise
Custom tags have 2 constraints:
-
Tag name must contain hyphen
-
Prototype must inherit from HTMLElement
Similarly can play with:
document.body.innerHTML = '<template id="tmpl"><p>How <em>you</em> doin?</p><style>em {font-size: 200%;}</style></template><div class="container"></div>';
// Grab our template full of markup and styles
var tmpl = document.querySelector('#tmpl');
// Create a prototype for a new element that extends HTMLElement
var HowYouDoinProto = Object.create(HTMLElement.prototype);
// Setup our Shadow DOM and clone the template
HowYouDoinProto.createdCallback = function() {
var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
};
// Register our new element
var HowYouDoin = document.registerElement('how-you-doin', {
prototype: HowYouDoinProto
});
document.querySelector('.container').innerHTML = '<how-you-doin/>';
Can get:
<div class="container">
<how-you-doin>
#shadow-root (open)
<p>How <em>you</em> doin?</p>
<style>em {font-size: 200%;}</style>
</how-you-doin>
</div>
Presented content is also as we wished: a large-sized you
document.registerElement in above example is Custom Elements feature. As for importNode(), it's just a normal DOM API (not part of Custom Elements), used to clone nodes, otherwise template is one-time use
As for HTML Imports, it's even less important, also has CORS, simple component loading solution, not much different from ajax manually loading components. Before HTTP2.0 era truly arrives, production environment better not split into multiple files
P.S. If interested in HTML Imports, can check online Demo and reference materials
V. Vue and Web Components
Up to now, all examples mentioned above, however you look at it seems like Vue component definition, yes, because Vue follows partial Web Components specification in implementation, such as slot in Shadow DOM:
You may have noticed that Vue components are very similar to Custom Elements, which are part of the Web Components Spec. That's because Vue's component syntax is loosely modeled after the spec. For example, Vue components implement the Slot API and the is special attribute.
Mainly 2 differences:
- The Web Components Spec is still in draft status, and is not natively implemented in every browser. In comparison, Vue components don't require any polyfills and work consistently in all supported browsers (IE9 and above). When needed, Vue components can also be wrapped inside a native custom element.
- Vue components provide important features that are not available in plain custom elements, most notably cross-component data flow, custom event communication and build tool integrations.
Because Web Components specification is not yet mature, and support is not optimistic, cannot be put into production without polyfills, Vue relies on build tools to cross environment compatibility problems, doesn't rely on browser feature support, but at the same time abandons Shadow DOM encapsulation and other Web Components core advantages
Additionally, Web Components is relatively low-level component specification, Vue besides defining component specification, also provides component communication, data binding and other higher-level solutions
VI. Online Demo
Address: http://www.ayqy.net/temp/web-components/image-slider.html
P.S. A very cleverly implemented pure CSS image slider component with indicators, very interesting, refreshed author's view on general adjacent sibling selector (E ~ F)
Reference Materials
-
A Guide to Web Components: Very good Web Components guide
-
Shadow DOM W3C Editor's Draft 14 November 2017: Shadow DOM editor's draft
No comments yet. Be the first to share your thoughts.