What the hell are Web Components?

Tim Perry
Tech Lead & Open-Source Champion at Softwire

Web Components

Web Components

<div class="bs-example bs-navbar-top-example">
  <nav class="navbar navbar-default navbar-inverse" role="navigation">
    <div class="container-fluid">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed"
                data-toggle="collapse"
                data-target="#bs-example-navbar-collapse-6">
        <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6">
        <ul class="nav navbar-nav">
          <li class="active"><a href="/1">Home</a></li>
          <li><a href="/2">Link</a></li>
          <li><a href="/3">Link</a></li>
        </ul>
      </div>
    </div>
  </nav>
</div>

Web Components

<nav-bar>
  <ul>
    <li><a href="/1">Home</a></li>
    <li><a href="/2">Link</a></li>
    <li><a href="/3">Link</a></li>
  </ul>
</nav-bar>        
Softwire

Web Components

  • <Template>
  • HTML Imports
  • Shadow DOM
  • Custom Elements

Current Templates

<div id="img-with-caption-template" style="display: none">
  <img src="/default-image.png" />
  <h3 class="title">Super cool image!</h3>
</div>

Current Templates (Knockout)

<script type="text/html" id="img-with-caption">
  <img src="/default-image.png" />
  <h3 class="title">Super cool image</h3>
</script>

<Template>

<template id="img-with-caption">
  <img src="/default-image.png" />
  <h3 class="title">Super cool image</h3>
</template>

<Template>

<template id="img-with-caption">
  <img src="/default-image.png" />
  <h3 class="title">Super cool image</h3>
</template>

<script type="text/javascript">
  var template = document.querySelector("#img-with-caption");
  var content = document.importNode(template.content, true);
  document.body.appendNode(content);
</script>

HTML Imports

<head>
  <link rel="import" href="otherFile.html" />
</head>

HTML Imports

index.html

<head>
  <link rel="import"
        href="import.html" />
</head>

import.html

Some HTML!

<style>
  h1 { font-size: 500%; }
</style>

<script>
window.aThing = function () {
  ...
}
</script>

Shadow DOM

Shadow DOM

Some boring content
<div id="myDiv">Some boring content<div>

<script type="text/javascript">
  var div = document.querySelector("#myDiv")
  var shadow = div.createShadowRoot();
  
  shadow.innerHTML = '<h3>Dom-invisible headline!</h3>';
</script>

Shadow DOM

Real content
<div id="myDiv2">
  Real content
</div>

<script type="text/javascript">
  var div = document.querySelector("#myDiv2")
  var shadow = div.createShadowRoot();
  shadow.innerHTML =
  "<h3>" +
    "Originally: <content></content>" +
  "</h3>";
</script>

Custom Elements

document.registerElement('nav-bar');
<nav-bar>
  <ul>
    <li>Home</li>
    <li>Link</li>
    <li>Link</li>
  </ul>
</nav-bar>

Custom Elements

var NavBarPrototype = Object.create(HTMLElement.prototype);

NavBarPrototype.doThings = function () { ... }

document.registerElement('nav-bar', {
    prototype: NavBarPrototype
});

...

document.querySelector("nav-bar#my-menu").doThings();

Custom Elements

var NavBarPrototype = Object.create(HTMLElement.prototype);

NavBarPrototype.createdCallback = function () { ... }

NavBarPrototype.attachedCallback = function () { ... }

NavBarPrototype.detachedCallback = function () { ... }

NavBarPrototype.attributeChangedCallback = function () { ... }

document.registerElement('nav-bar', {
    prototype: NavBarPrototype
});

Custom Elements

var NavBarPrototype = Object.create(HTMLElement.prototype);

NavBarPrototype.createdCallback = function () {
  this.innerHTML = '<div class="bs-example bs-navbar-top-example"> \
                       <nav class="navbar navbar-default navbar inverse"> \
                       ...';
};

document.registerElement('nav-bar', {
  prototype: NavBarPrototype
});
<template id="navBarTemplate">
  <div class="bs-example bs-navbar-top-example">
    <nav class="navbar navbar-default navbar inverse">
      ...
      <content></content>
      ...
    </nav>
  </div>
</template>

<script>
  var NavBarPrototype = Object.create(HTMLElement.prototype);
  
  NavBarPrototype.createdCallback = function () {
    var template = document.querySelector("#navBarTemplate");
    var content = document.importNode(template.content, true);
    this.createShadowRoot().appendNode(content);
  };
  
  document.registerElement('nav-bar', {
    prototype: NavBarPrototype
  });           
</script>             

Let's put it together

Actually using this?

Specced Implementation
Polyfill Chrome / Opera Firefox Safari IE
Templates Stable Stable 8
HTML Imports Stable Behind flag
Custom Elements Stable Behind flag
Shadow DOM Stable Behind flag

(From Are We Componentized Yet?)

Frameworks

  • Knockout
  • Ember
  • Angular (in 2.0)

Web components!


Tim Perry
Tech Lead & Open-Source Champion at Softwire