Introduction to Web Components

W3C Working Draft 22 May 2012

This version
Latest version
Latest editor's draft
Previous version
Revision history
Discuss on (Web Applications Working Group)
File bugs ('s Bugzilla)
Dominic Cooney, Google, <>
Dimitri Glazkov, Google, <>


This document is a non-normative reference, which aims to provide an overview of how Web Components work. It summarizes the normative information in the respective specifications in an easy-to-digest prose and illustration.

Status of this Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at

This document was published by the Web Applications Working Group as a First Public Working Draft. If you wish to make comments regarding this document, please send them to (subscribe, archives). All feedback is welcome.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of Contents

  1. 1 About this Document
  2. 2 Introduction
  3. 3 Templates
  4. 4 Decorators
    1. 4.1 Events in Decorators
    2. 4.2 Decorators Example
  5. 5 Custom Elements
    1. 5.1 Presentation
    2. 5.2 Using Custom Elements in Markup
    3. 5.3 Using Custom Elements in Script
    4. 5.4 Element Upgrade
    5. 5.5 Lifecycle Methods
    6. 5.6 Extending Custom Elements
    7. 5.7 Error Handling
  6. 6 Shadow DOM
    1. 6.1 Content and Shadow Elements
    2. 6.2 Multiple Shadow Subtrees
    3. 6.3 CSS and Shadow DOM
    4. 6.4 Events in Shadow DOM
    5. 6.5 Making More Shadows
  7. 7 Decorators vs. Custom Elements
  8. 8 External Custom Elements and Decorators
  9. 9 Isolation, Confinement and Encapsulation
  10. 10 Example
  11. Appendix A. Interfaces
  12. Appendix B. HTML Elements
  13. Appendix C. Custom Element Constructor Properties
  14. Acknowledgements

1 About this Document

As mentioned earlier, this document is a work in progress. It was initially written as a thought exercise to tie up all concepts, associated with the Web components into one coherent, non-normative narrative. Then, each concept will be refined and developed into a separate normative document, subsequently feeding back changes, concepts, and terms into this document. This iterative process is still continuing today, and produced the following specifications:

Once all information is extracted into the respective normative documents and this document is updated to accurately describe, as well as summarize the information in the normative documents, this document will be finalized and become the actual introduction for Web components.

2 Introduction

The component model for the Web (also known as Web Components) consists of four pieces designed to be used together to let web application authors define widgets with a level of visual richness not possible with CSS alone, and ease of composition and reuse not possible with script libraries today.

These pieces are:

Both decorators and custom elements are called components.

3 Templates

The <template> element contains markup intended to be used later—by script or some other template-aware consumer (like <decorator> and <element> elements that are described later).

The content of the <template> element is parsed by the parser, but it is inert: scripts don't run, images aren't downloaded, and so on. The <template> element is not rendered.

In script the element has one property, content, which contains the inert DOM structure, defined by the template.

For example, a Web developer may want to define the DOM structure that is created multiple times in the document, and then create an instance of it anytime it's needed.

<template id="commentTemplate">
        <img src="">
        <div class="comment"></div></div>

var t = document.querySelector("#commentTemplate");
// Populate content and img[src] values in the template.
// …

Appending inert DOM to a document node makes it go "live", as if the DOM tree was just parsed from markup (setting innerHTML).

4 Decorators

A decorator is something that enhances or overrides the presentation of an existing element. Like all presentation aspects, the application of decorators is controlled by CSS. However, being able to specify the extra presentation using markup is unique to decorators.

The <decorator> element contains a <template> element, which specifies the markup to use for rendering the decoration.

<decorator id="fade-to-white">
        <div style="position: relative;">
            <style scoped>
                #fog {
                    position: absolute;
                    left: 0;
                    bottom: 0;
                    right: 0;
                    height: 5em;
                    background: linear-gradient(
                    bottom, white 0%, rgba(255, 255, 255, 0) 100%);
            <div id="fog"></div>

The <content> element is the point where the content of the decorated element (element's children) should be inserted.

Decorators are applied using the decorator CSS property:

.poem {
    decorator: url(#fade-to-white);
    font-variant: small-caps;

This decorator and stylesheet would cause the following markup:

<div class="poem">
    Two roads diverged in a yellow wood,<br></div>

To be rendered as if it was this markup (omitting user agent styles for brevity):

<div class="poem" style="font-variant: small-caps;">
    <div style="position: relative;">
        Two roads diverged in a yellow wood,<br><div style="position: absolute; left: 0; "></div>

If the document changes so that the selector with the decorator property no longer matches—typically when a selector with the property no longer matches or the rule with this property was changed in the inline styles, the decorator is unapplied, returning the rendering of the element back to the pre-decoration state.

Even though the decorator CSS property can point to any resource on the Web, the decorator will not be applied unless its definition is loaded by this document.

The markup that generates the presentation is limited to be purely presentational: it may never run script (including inline event hanlders) and it cannot be editable.

4.1 Events in Decorators

Decorators can also attach event handlers to implement interactivity. Because the decorators are transient, it is not useful for the decorator to attach event listeners to the nodes in the template or rely on any state, since it perishes any time decorator is applied or unapplied.

Instead, decorators register event listeners with an event controller. To register an event listener with an event controller, the template includes a <script> element. The script is run once when the decorator element is parsed or inserted into the document, or loaded as part of an external document.

Fig. Event handler registration

The event controller is passed to the script in the this pointer.

<decorator id="decorator-event-demo">
        function h(event) {
        this.listen({selector: "#b", type: "click", handler: h});
        <button id="b">Bar</button>

The call to listen means that when the button with id b is clicked, the handler h is called.

The event controller routes events originating in any of the places that the decorator is applied to the event handler.

Fig. Event routing and retargeting

When the event listener is called, the target of the event is the content that the decorator was applied to, and not content from the template. For example, given the decorator specified above, this content:

<span style="decorator: url(#decorator-event-demo);">Foo</span>

Would be rendered like this:


Clicking on the button would show a dialog containing [object HTMLSpanElement].

This retargeting is necessary because the decorator specifies presentation; it does not affect the structure of the document. Since it is in the document, the content the decorator is applied to is the target of the event.

Similarly, if script changes the content of the template later, this doesn't have any effect on the decorator, just like setting the textContent of a <script> element doesn't cause the script to execute again.

The decorators have no way to change the state of the decorating DOM tree, other than triggering application of a different decorator.

4.2 Decorators Example

Here is an example of how decorators could be used to implement a simple variant of the details element:

details {
    decorator: url(#details-closed);
details[open] {
    decorator: url(#details-open);

<decorator id="details-closed">
            selector: "#summary", type: "click",
            handler: function (event) {
       = true;
        <a id="summary">
            &gt; <content select="summary:first-of-type"></content>

<decorator id="details-open">
            selector: "#summary", type: "click",
            handler: function (event) {
       = false;
        <a id="summary">
            V <content select="summary:first-of-type"></content>

This uses two decorators. One presents the details view closed; the other presents the details view open. Each decorator uses an event handler to respond to clicks by toggling the open state of the element. The content element's select attribute will be explained in detail later.

5 Custom Elements

Custom elements are new types of DOM elements that can be defined by authors.

Custom elements can define presentation aspects like decorators. Unlike a decorator, which can be applied or unapplied to a given element, the element's type is fixed. So custom elements can also define new state and behavior, which decorators can't do because of their ephemeral nature.

The element element defines a custom element. It specifies the type of element it's a refinement of using the extends attribute:

<element extends="button" name="x-fancybutton"></element>

The extends attribute specifies the tag name of the kind of element this element is an extension of. Instances of the custom element will have the tag name specified here.

The name attribute specifies the name of the custom element, by which it will be referred to in markup. The naming space of the name is the same as element tag names, and to avoid collisions, the x- prefix is required for custom element value.

Different user agents interpret HTML elements differently, however all of their interpretations are guided by the semantics of HTML.

Because not all user agents support custom elements, authors should extend the HTML element that has the closest meaning to their new kind of element. For example, if they are defining a custom element that is interactive and responds to clicks by doing some action, they should extend button.

When there isn't a HTML element that is semantically close to their custom element authors should extend a semantically neutral element like span.

5.1 Presentation

A custom element may optionally include a template:

<element extends="button" name="x-fancybutton">
        <style scoped>
            :host { display: contents; }
            div.fancy {
        <div class="fancy">
            <div id="t"></div>
            <div id="l"></div>
            <div id="b"></div>
            <div id="r"></div>

If a custom element includes a template, a copy of the template content is inserted into the custom element's shadow DOM by the generated constructor. Shadow DOM is described below.

5.2 Using Custom Elements in Markup

Because custom elements use existing HTML tag names—div, button, option, and so on—we need to use an attribute to specify when an author intends to use a custom element. The attribute name is is, and its value is the name of a custom element. For example:

<element extends="button" name="x-fancybutton">  <!-- definition --></element>

<button is="x-fancybutton" onclick="showTimeClicked(event);">  <!-- use -->
    Show time

5.3 Using Custom Elements in Script

You can instantiate a custom element from script using the standard document.createElement facility:

var b = document.createElement("x-fancybutton");
alert(b.outerHTML); // will display '<button is="x-fancybutton"></button>'

Also, you can specify the constructor attribute on the <element> element to explicitly add a JavaScript property for the element constructor on the window object. That constructor can then be used to create instances of the custom element:

<element extends="button" name="x-fancybutton" constructor="FancyButton"></element>


var b = new FancyButton();

A custom element can expose API to script by putting properties on the constructor's prototype object, in a <script> that is nested inside the <element> element:

<element extends="button" name="x-fancybutton" constructor="FancyButton"><script>
    FancyButton.prototype.razzle = function () {
    FancyButton.prototype.dazzle = function () {
    var b = new FancyButton();
    b.textContent = "Show time";
    b.addEventListener("click", function (event) {;

In order to provide graceful fallback behavior, the this pointer within the <script> element points to parent HTMLElementElement instance:

<element extends="table" name="x-chart" constructor="Chart">
        if (this === window)
            // Use polyfills to emulate custom elements.
            // …
        else {
            // …

Mechanically, the code inside of the <script> element when it is a child of either <element> or <decorator> elements is executed like this:

(function() {
    // code goes here.

In situations where having constructors on window object is undesirable, the custom element author can use generatedConstructor property of the HTMLElementElement:

<element extends="table" name="x-chart">
        // …
        var Chart = this.generatedConstructor;
        Chart.prototype.shizzle = function() { /* … */ };
        // …

One cannot create a custom element by setting an is attribute on an existing DOM element. Doing so will result in a no-op:

var div = document.createElement("div");
div.setAttribute("is", "foo");
alert(; // displays null
alert(div.outerHTML); // displays <div></div>

5.4 Element Upgrade

As the definition of a custom element is loaded, each element with the is attribute set to the name of that custom element is upgraded to the custom element. The upgrade process should be perceptually equivalent to removal of the element from the document and its replacement by the custom element instance.

As each element is replaced, a non-bubbling, non-cancellable event is dispatched to the element that has been removed. Scripts that want to delay interacting with part of a document until the custom elements are present can listen to this event:

function showTimeClicked(event) {
    // may be an HTMLButtonElement or a FancyButton

    if (! {
        // razzle, part of the FancyButton API, is missing
        // so upgrade has not happened yet'upgrade', function (upgradeEvent) {


function showTime(b) {
    // b is FancyButton

Authors who want to avoid the flash of unstyled content can use CSS to change the presentation of the ordinary element until the custom element is loaded.

5.5 Lifecycle Methods

A custom element can optionally subscribe to these four lifecycle callbacks:

The callbacks are invoked with this as the instance element.

The inserted and removed callbacks may be called multiple times if the element as the element is inserted and removed from the tree.

You can subscribe to these callbacks by invoking HTMLElementElement.lifecycle method:

<element extends="time" name="x-clock">
// …

            inserted: function() { this.startUpdatingClock(); },
            removed: function() { this.stopUpdatingClock(); }

// …

5.6 Extending Custom Elements

In addition to HTML elements, you can also extend a custom element by specifying the custom element's name as the value of the extends attribute in the <element> element:

<element extends="x-clock" name="x-grandfatherclock"></element>

5.7 Error Handling

There are several opportunities for error when setting up custom elements:

6 Shadow DOM

Shadow DOM is a tree of DOM nodes. Shadow DOM can be applied to a custom element declaratively, by including a template, or to any element imperatively using JavaScript.

When an element has shadow DOM, the element's children are not rendered; the content of the shadow DOM is rendered instead.

6.1 Content and Shadow Elements

Any shadow DOM subtree can specify insertion points for element's children by using a <content> element:

    <div class="stuff">
        <content><!-- all children will appear here --></content>

The <content> element acts as an insertion point for rendering only—it does not change where the elements appear in DOM. When rendering, the element's children just appear in place of the <content> element. And yes, you can have more than one <content> in the shadow DOM subtree! The select attribute gives you a handy way to choose which children appear at which insertion point. If there is more than one <content> element, the tree order dictates when each of these elements takes a pass at selecting the children. Once the child is selected to be rendered at one insertion point, it can't be claimed by another one.

    <content select=""><!-- all children will
        appear here --></content>
    <div class="cool">
        <content select=".cool"><!-- all .cool children
            (except the ones that are appear here --></content>
    <div class="stuff">
        <content><!-- all remaining children will
            appear here --></content>

6.2 Multiple Shadow Subtrees

Any element can have more than one shadow DOM subtree. Don't look so puzzled! Suppose you are extending a DOM element that already has a shadow DOM subtree. What happens to that poor old tree? We could just ditch it for the new arboreal hotness, but what if you don't want to? What if you want reuse it?

For this noble purpose, we have a special <shadow> element, which acts as an insertion point for the, you guessed it, the previously applied shadow DOM subtree of this element (also known as the older tree). For instance, you can take existing range slider (that's <input type="range">) and extend it, adding your extra shadow schmutz to it:

    <shadow><!-- range slider renders here --></shadow>
    <div class="ticks"></div>

Since an element can have multiple shadows, we need to understand how these shadows interact with each other and what effect these interactions have on rendering of the element's children.

First, the order in which the shadow DOM subtrees are applied is important. Because you cannot remove a shadow DOM, the order is typically like this:

  1. element shadow DOM (I got here first, nyah!)
  2. shadow DOM of the element sub-class
  3. shadow DOM of the element sub-sub-class
  4. some shadow DOM added using script
  5. decorator shadow (applied and removed with CSS rules—not technically a shadow DOM, but can, too, have <content> and <shadow> elements)

Next, we take this stack of shadow DOM subtrees and traverse it backwards, starting with the last-applied (or youngest) subtree. Each <content> instance, encountered in tree order, grabs the element's children that it needs as usual.

This is where things get interesting. Once we're done shuffling the children into their right places to render, we check and see if we have a <shadow> element. If we don't, we're done.

If we do, we plop the next shadow subtree in our list in place of the <shadow> element, and rinse-repeat first replacing <content> insertion points, then <shadow> until we reach the start of the list.

And then—ta-da!—we have our wondrous shadow DOM Yggdrasil, ready for rendering.

Here's an easy way to remember how this works:

6.3 CSS and Shadow DOM

When building a custom element, you often want to prevent document styles from interfering with what you've painstakingly crafted.

Lucky for you, the shadow DOM subtree is surrounded by an invisible boundary, only letting the user agent styles apply by default. The inheritance still works as usual—more on that later.

You can relax this boundary with the apply-author-styles attribute on the <template> element. With the attribute present, document's author styles start applying in the shadow DOM subtree.

Conversely, you can make the boundary even stronger by setting the reset-style-inherifance attribute on the <template> element. With the attribute present, all styles are reset to initial values at the shadow boundary. No more need for lengthy reset stylesheets! Just set the attribute and start with a clean slate.

There is a similar boundary between the <content> element and element's children, rendered in its place. The styles from the shadow DOM subtree do not apply to the element's children.

The magic boundary also prevents selectors from reaching into the shadow DOM subtree, skipping it altogether. For example, if <div id="foo"> had this shadow DOM subtree:

<a href="">shadow link</a>

and a child

<a href="">light link</a>

both div#foo>a and div#foo a will select the child (light link), not the anchor in the shadow DOM (shadow link).

If the component authors wish to allow some styling of the shadow DOM subtree by the component users, they can do so with CSS variables. The variable definitions specified on the shadow DOM host element are also resolved inside of the shadow DOM subtree.

6.4 Events in Shadow DOM

To ensure that the elements of the shadow DOM subtree are not exposed outside of the subtree, there's a fair bit of work that happens while dispatching an event from inside of the subtree.

First, some events (like mutation and selectstart events) are just plain prevented from escaping out of the shadow DOM subtree—they are never heard from the outside.

Those events that do cross the shadow DOM boundary are retargeted—their target and relatedTarget values are modified to point to the element that hosts the shadow DOM subtree.

In some cases, like DOMFocusIn, mouseover, mouseout events have to be given extra attention: if you're moving a mouse between two elements inside of the shadow subtree, you don't want to be spamming the document with these events, since they will appear as non-sensical babbling after the retargeting (what? the element just reported that the mouse just moved from itself back to itself?!)

6.5 Making More Shadows

As implied before, you can always add a shadow DOM subtree to any DOM element in one line of code:

var shadow = new ShadowRoot(anyElement);

This does two things:

  1. Creates a brand-spanking-new ShadowRoot instance, which you should imagine as this shadowy, invisible other side of your element. It's like a tiny document that lives inside of our custom element, and serves as the root of your shadow DOM subtree.
  2. Sets anyElement as the host of this newly created shadow DOM subtree.

The important thing to remember is that while you can add new shadow DOM subtrees this way, you can never remove them: they just keep stacking up.

7 Decorators vs. Custom Elements

Decorator shadows are never accessible with DOM. When the decorator is created, the shadow DOM subtree is placed in a cold, dark place—for storage. Once the decorator is applied to an element, this shadow DOM subtree is used to produce the rendering, but its nodes are never accessible from script. You can, however listen to events that happen inside the decorator shadow using EventController.

An easy way to think of the decorator shadow is a projection. You can see it, but never can actually touch it.

On the other hand, the custom element shadow (or any shadow DOM subtree created using script) is a real DOM tree that you as the custom element author can change as you please.

Another important difference between the two is the fact that you can unapply a decorator. On the other hand, once you've instantiated a custom element, its qualities—including its shadow DOM subtree—are inherent part of element's identity.

8 External Custom Elements and Decorators

Custom elements and decorators can be loaded from external files using the link tag:

<link rel="components" href="goodies.html">

Only decorator elements, element elements and script elements are interpreted by the UA. The DOM of this document is not available to script. The origin of the embedding document is used as the origin of the embedded document. Script runs as though it was async defer. The custom element definitions and decorators are not made available until the scripts have run. Documents which are retrieved cross-origin use CORs to determine that the definitions are designed to run cross-site.

9 Isolation, Confinement and Encapsulation

Component isolation can be viewed as combination of two parts:

Component encapsulation is partially enforced with shadow DOM, ensuring that shadow DOM nodes never appear in the event dispatch, range, focus-related DOM accessors or any APIs that query DOM nodes. It is up the author of the component to choose whether the inner state is exposed.

Component confinement is trickier, but possible using existing primitives, such as iframe or workers. The general solution would be to treat the component as the corruptible agent, which is responsible for the component user interface and interaction with the document. The component would then load a worker (or an iframe) and communicate with it using postMessage:

<!--- located at -->
<element name="x-adore-button" extends="button">
        var service = new Worker("");
        service.onmessage = function(event) {
            // process responses from the service.
        // set up UI.
        // start interacting with the worker.
    <template>I adore this</template>

10 Example

Suppose we we want to display a clickable map of timezones instead of a select element. Here's how one could implement this using decorators:

<decorator id="timezone-map">
        var timezones = ["PST",  ];

        function createHandler(timezone)
                selector: "#" + timezone,
                type: "click",
                handler: function() {
                    // Decorators are late-bound, we must check for type.
                    if (this instanceof HTMLSelectElement)
                        this.selectedIndex = this[timezone].index;

        timezones.forEach(createHandler, this);
            <g id="worldShapes"></g>
            <g id="timezoneShapes">
                <path id="PST">
                <path id="CST">

You would apply this decorator as:

select.timezones {
    decorator: url(#timezone-map);

provided that there's the following markup in the document:

<select class="timezones">

And here's the implementation using custom elements:

<element extends="select" name="x-timezone-map" constructor="MapSelector">
            created: function(shadowRoot) {
                var select = shadowRoot.shadowHost;
                var timezones = shadowRoot.querySelector("#timezoneShapes");
                timezones.addEventListener("click", function(event) {
                    if ( != this)
                        select.selectedIndex = select[].index;

        MapSelector.prototype.isDaylightSaving = function() { /* … */ }
            <g id="worldShapes"></g>
            <g id="timezoneShapes">
                <path id="PST">
                <path id="CST">

You would use this custom element like so:

<select is="x-timezone-map">

For more examples, take a look at the Web Components Samples.

Appendix A. Interfaces

partial interface HTMLElement {
    readonly attribute DOMString is;

interface HTMLTemplateElement : HTMLElement {
    readonly attribute DocumentFragment content;

interface HTMLDecoratorElement : HTMLElement {
    attribute bool applyAuthorStyles;
    void listen(ListenInit listenInitDict);
dictionary ListenInit {
    DOMString type;
    DOMString selector;
    EventHandler handler;

interface HTMLContentElement : HTMLElement {
    attribute DOMString select;

interface HTMLElementElement : HTMLElement {
    attribute DOMString extends;
    attribute DOMString name;
    attribute bool applyAuthorStyles;
    readonly attribute Function generatedConstructor;
    void lifecycle(LifecycleInit lifecycleInitDict);
    void reflectAttribute(DOMString attributeName,
    DOMString propertyName, ChangeCallback changeCallback);
    void setupEvent(DOMString eventName);
dictionary LifecycleInit {
    Function attributeChanged(
            DOMString name,
            DOMString newValue,
            DOMString oldValue);
    Function created(ShadowRoot shadowRoot);
    Function inserted();
    Function removed();
[Callback=FunctionOnly, NoInterfaceObject]
interface ChangeCallback {
    void handleEvent(DOMString name, DOMString newValue, DOMString oldValue);

interface HTMLShadowElement : HTMLElement {

[Constructor(in HTMLElement element) raises (DOMException)]
interface ShadowRoot : DocumentFragment {
    Element getElementById(in DOMString elementId);
    NodeList getElementsByClassName(in DOMString tagName);
    NodeList getElementsByTagName(in DOMString className);
    NodeList getElementsByTagNameNS(DOMString namespace, DOMString localName);
    attribute bool applyAuthorStyles;
    attribute bool resetStyleInheritance;
    readonly attribute Element activeElement;
    readonly attribute Selection selection;
    attribute DOMString innerHTML;
ShadowRoot implements NodeSelector;

Appendix B. HTML Elements


Represents an insertion point in a shadow DOM subtree. The insertion point is replaced with the elements' children at rendering time. The <content> element itself is never rendered.

Context: Where flow content is expected.

Children: anything (fallback content)


select—the value is a list of selector fragments, addressing immediate children of the element.


Defines a new decorator. Typically, you would also give it an id attribute to make it addressable from CSS.

Context: anywhere in the document.

Children: <template> and <script>


apply-author-styles—if true, the author styles of the document apply to the shadow DOM subtree of the element. If false (default), the author styles do not apply.


Defines a new custom element.

Context: anywhere in the document.

Children: <template> and <script>


constructor—name of the generated constructor function. If specified, a key by this name is added to the window object, referring to the element's generated constructor.

extends—tag name of the element or a defined custom element constructor name that the new custom element extends.

name—the name of the custom element constructor that is generated by this definition.

apply-author-styles—if true, the author styles of the document apply to the shadow DOM subtree of the element. If false (default), the author styles do not apply.


Specifies a shadow insertion point, where the older shadow DOM subtree in element's shadow DOM tree stack is rendered. The <shadow> element itself is never rendered.

Context: Where flow content is expected.

Children: anything (fallback content).


Defines an inert chunk of DOM that can then be used for creating DOM instances in an unknown parsing context.

Context: anywhere in the document.

Children: any element.

Appendix C. Custom Element Constructor Properties

Here are some more properties of the generated constructor and FancyButton instances:

typeof FancyButton  "function"{})  throws
Object.getPrototypeOf(FancyButton.prototype) ===
   HTMLButtonElement.prototype  true

document.body.lastChild === b  true
b.tagName  "button"
b.outerHTML  "<button is="FancyButton"></button.html>"
b instanceof FancyButton  true
b instanceof HTMLButtonElement  true


Thanks to Alex Komoroske, Alex Russell, Darin Fisher, Dirk Pranke, Divya Manian, Erik Arvidsson, Hayato Ito, Hajime Morita, Ian Hickson, Jonas Sicking, Rafael Weinstein, Roland Steiner, and Tab Atkins for their comments and contributions to this document.