Hi I'm Rob, – I'll be your guide today.



Hi I'm Rob, – I'll be your guide today.

0 1


webcomponents-cascade

Slides for my Web Components workshop at Cascade SF

On Github robdodson / webcomponents-cascade

Hi I'm Rob,

I'll be your guide today.

robdodson.me

@rob_dodson

robdodson

Freelance front-end developer

I blog at...

We're going to cover a lot of material...

This presentation contains native Web Components and will only display properly in Chrome Canary.

Be sure to enable the following in chrome://flags

Experimental Web Platform features

Experimental JavaScript

HTML Imports

Within this talk...

Web Components?

The Specs

Use 'em, Today!

What are web components...

The 4 underlying technologies that collectively make up web components

Tools that we can use to start experimenting...

Code Ahead!

How do you use Bootstrap?

How do you use Foundation?

How do you use Kendo UI?

How do you use jQuery UI?

1. Go to Docs

<nav class="navbar navbar-default" role="navigation">
  <!-- Brand and toggle get grouped for better mobile display -->
  <div class="navbar-header">
    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
      <span class="sr-only">Toggle navigation</span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">Brand</a>
  </div>

  <!-- Collect the nav links, forms, and other content for toggling -->
  <div class="collapse navbar-collapse navbar-ex1-collapse">
    <ul class="nav navbar-nav">
      <li class="active"><a href="#">Link</a></li>
      <li><a href="#">Link</a></li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
        <ul class="dropdown-menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li><a href="#">Separated link</a></li>
          <li><a href="#">One more separated link</a></li>
        </ul>
      </li>
    </ul>
    <form class="navbar-form navbar-left" role="search">
      <div class="form-group">
        <input type="text" class="form-control" placeholder="Search">
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
    <ul class="nav navbar-nav navbar-right">
      <li><a href="#">Link</a></li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
        <ul class="dropdown-menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </li>
    </ul>
  </div><!-- /.navbar-collapse -->
</nav>

2. Copy all the things

3. Receive Widget

We can do better

<nav class="navbar navbar-default" role="navigation">
  <!-- Brand and toggle get grouped for better mobile display -->
  <div class="navbar-header">
    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
      <span class="sr-only">Toggle navigation</span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">Brand</a>
  </div>

  <!-- Collect the nav links, forms, and other content for toggling -->
  <div class="collapse navbar-collapse navbar-ex1-collapse">
    <ul class="nav navbar-nav">
      <li class="active"><a href="#">Link</a></li>
      <li><a href="#">Link</a></li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
        <ul class="dropdown-menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li><a href="#">Separated link</a></li>
          <li><a href="#">One more separated link</a></li>
        </ul>
      </li>
    </ul>
    <form class="navbar-form navbar-left" role="search">
      <div class="form-group">
        <input type="text" class="form-control" placeholder="Search">
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
    <ul class="nav navbar-nav navbar-right">
      <li><a href="#">Link</a></li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
        <ul class="dropdown-menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </li>
    </ul>
  </div><!-- /.navbar-collapse -->
</nav>

2. Copy all the things

<twbs-navbar>
  <a href="#">Home</a>
  <a href="#">About</a>
  <a href="#">Bacon</a>
</twbs-navbar>

2. Use the thing

Web Components!

1. Create your own HTML Elements

2. Encapsulate your styles

3. React with lifecycle callbacks

"Umbrella" term

Collectively, let us do cool stuff...

Web Components use the same tools that the browser makers use.

pie-chart tag...

You can see why this could be a big deal...

Web Components Revolution...

<chart-pie></chart-pie>

Imagine you're building a data viz library

<mark-down>   ## Oh hai!   ### How _you_ doin?   [Link me!](foo.com) </mark-down>
## Oh hai! ### How _you_ doin? [Link me!](foo.com)

Web Components

There's actually 4 technologies that make up web components

And we're going to go through each of them

Templates

Scaffolding

Shadow DOM

Encapsulation

Custom Elements

Extensions

Imports

Packaging

Templates: Just like mustache

Shadow DOM: Some things public and other things private

Custom Elements: The interface

Templates +

Shadow DOM

Custom Elements

Imports get everything on the page

Templates

Templates are inert chunks of DOM that can be reused.

Template Basics

<template>
  <p>Once upon a time...</p>
  <img src=""/> <!-- Fill me in when you're ready -->
  <script>
    alert("I'm chillin."); // Totally inert!
  </script>
</template>

The Content Keyword

Using Templates

<template id="my-template">
  <img src=""/>
  <p>Templates. Full of WIN!</p>
  <script> alert("I'm alive!") </script>
</template>

<script>
  var tmpl = document.querySelector("#my-template");
  tmpl.content.querySelector("img").src = "corgi.gif";
  document.body.appendChild(tmpl.content.cloneNode(true));
</script>
Run

Templates. Full of WIN!

Gotchas

No Built-In Data Interpolation

{{ }} tags don't do anything...yet

Nested Templates Are Not Automatically Activated

You'll have to append each separately

Templates

Scaffolding

Shadow DOM

Encapsulation

Custom Elements

Extensions

Imports

Packaging

Shadow DOM

The Shadow DOM provides style and markup encapsulation.

Take some HTML and CSS nodes, bundle them together

Styles are scoped to the node

HTML cannot be traversed by external javascript

Same tech as browser makers

It is the same technology used by browser makers to implement tags like <video> and <textarea>.

<video>'s secret DOM

<video src="./bunny.webm" controls></video>

Shadow Host

The node that contains all of our shadow DOM

Shadow Root

The first node in the shadow DOM

Shadow Boundary

The barrier that protects our shadow DOM

element.createShadowRoot()

Our first shadow dom

<div class="widget">Hello, world!</div>
<script>
  var host = document.querySelector(".widget");
  var root = host.createShadowRoot();
  root.innerHTML = "<em>I'm inside yr div!</em>";
</script>
Run
Hello, world!

Only descendants of the Shadow Root will be rendered.

Inspect with dev tools

Styles in the Shadow DOM are protected from the parent document.

Style Encapsulation

<template>
  <style>
    h3 { color: white; background: tomato; }
  </style>
  <h3>A Shadow H3 Header</h3>
</template>
Shadow
<script>
  var tmpl = document.querySelector("template");
  var host = document.querySelector(".widget");
  var root = host.createShadowRoot();
  root.appendChild(tmpl.content.cloneNode(true));
</script>

A Shadow H3 Header

An H3 Header

applyAuthorStyles (default: false)

false: Author styles will not affect your component.

true: Author styles will affect your component.

A Shadow H3 Header

An H3 Header

Toggle root.applyAuthorStyles:

These are good for broad changes but you probably also want to be able to expose specific elements for the user to style

resetStyleInheritance (default: false)

false: Inheritable styles will affect your component.

true: Inheritable styles will not affect your component.

A Shadow H3 Header

An H3 Header

Toggle root.resetStyleInheritance:

Styling :host

<template>
  <style>
    :host {
      border: 5px solid red;
    }
  </style>
  <h2>Oh hai!</h2>
</template>
Shadow

Oh hai!

Theming

<template>
  <style>
    :host(.skinny) h2 {
      font-family: 'Open Sans Condensed';
      letter-spacing: -0.09em;
    }
  </style>
  <h2>Oh hai!</h2>
</template>
Shadow

All jammed up

Custom Properties

<template>
  <style>
    h2 {
      font-family: var(header-font);
    }
  </style>
  <h2>Custom prop stylin'</h2>
</template>
Shadow
<style>
  body {
    var-header-font: Courier;
  }
</style>

Custom prop stylin'

Insertion points invite content from the host element into the Shadow DOM.

Use the <content> tag to create an insertion point.

Insertion Points

<template>
  <h2>A Wild <content></content> Appeared!</h2>
</template>
Shadow
<div class="widget">Jigglypuff</div>
Jigglypuff

A Wild Appeared!

A single content tag is kind of like a catch-all

Specific content can be targeted with the select attribute.

Select

<h3>Last Name: <content select=".last-name"></content></h3>
<h3>First Name: <content select=".first-name"></content></h3>
<h3><content select=""></content></h3>
Shadow
<div class="widget">
  Hello World
  <span class="first-name">Rob</span>
  <span class="last-name">Dodson</span>
</div>

Last Name:

First Name:

Hello Rob Dodson World

You can style into the shadow boundary with the “ hat ” and “ cat ” selectors.

The Cat and the Hat

<template>
  <h2>First Shadow DOM</h2>
  <content></content>
</template>
Shadow
<style>
  /* the hat */
  .widget ^ h2 { color: red; }

  /* the cat */
  .widget ^^ h2 { font-family: Courier; }
</style>

First Shadow DOM

Second Shadow DOM

Templates

Scaffolding

Shadow DOM

Encapsulation

Custom Elements

Extensions

Imports

Packaging

Custom Elements

Custom Elements are new tags that extend the browser.

Templates +

Shadow DOM

Custom Elements

document.register('tag-name', {   prototype: proto })

Tag name must have a dash

Proto must inherit from HTMLElement

Creating a Custom Element

var tmpl = document.querySelector("#some-template");

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

WidgetProto.createdCallback = function() {
  var root = this.createShadowRoot();
  root.appendChild(tmpl.content.cloneNode(true));
};

var Widget = document.register("my-widget", {
  prototype: WidgetProto
});

Using Your Element

<my-widget></my-widget> // OR

document.createElement("my-widget") // OR

new Widget()

Lifecycle Callbacks

createdCallback() When a new instance is created. Use like a constructor

enteredViewCallback()* When an element is added to the page*previously named enteredDocumentCallback

leftViewCallback()* When an element is removed from the page*previously named leftDocumentCallback

attributeChangedCallback(attrName, oldVal, newVal) When one of an element's attributes changes

Type Extension Elements

var MyButton = document.register("my-button", {
  extends: "button",
  prototype: Object.create(HTMLButtonElement.prototype)
});

Add your element to the page

<button is="my-button"></button>
var btn = document.createElement("button", "my-button");
var btn = new MyButton();
Called "Type Extension Elements"

Goodbye <element>... for now

<!-- Do not use! Will be removed. -->
<element name="my-widget">
  ...
</element>

It's taking a beauty nap

MailChimp

<mc-signup
  url="http://robdodson.us7.list-manage.com/subscribe/post"
  u="5727aa0eb1ccbf4ae68284189"
  id="6719a28b56">
</mc-signup>

Dashboards

<chart-pie values="[...]"></chart-pie>
<chart-doughnut values="[...]"></chart-doughnut>
<chart-polar-area values="[...]"></chart-polar-area>
<chart-radar values="[...]"></chart-radar>
<chart-line values="[...]"></chart-line>
<chart-bar values="[...]"></chart-bar>

Moment

Right now:
Formatted:
Oct 26, 1985: Oct 26, 1985
Btw, that was: Oct 26, 1985
<moment-now></moment-now>
<moment-format tokens="MMMM Do YYYY, h:mm:ss a">
  <moment-now></moment-now>
</moment-format>
<moment-format tokens="dddd, MMMM Do YYYY">
  <moment-parse>Oct 26, 1985</moment-parse>
</moment-format>
<moment-from>
  <moment-parse>Oct 26, 1985</moment-parse>
  <moment-now></moment-now>
</moment-from>

Templates

Scaffolding

Shadow DOM

Encapsulation

Custom Elements

Extensions

Imports

Packaging

Imports

Imports load external documents into your page.

<link rel="import"       href="my-import.html">

Use a link tag, just like CSS

Use rel type import

Importing Custom Elements

<head>
  <link rel="import" href="./imports/chart.html">
</head>
<body>
  <chart-pie></chart-pie> <!-- ready to rock -->
</body>

No need to check if the import is loaded

Templates

Scaffolding

Shadow DOM

Encapsulation

Custom Elements

Extensions

Imports

Packaging

Support

Templates

Shadow DOM

Custom Elements

* *

Imports

*

* Behind a flag

Use Chrome Canary

In chrome://flags

Experimental Web Platform features

Experimental JavaScript

HTML Imports

Show Shadow DOM in Developer Tools

Use 'em Today!

Polymer

A collection of polyfills which let us use Web Components in all modern browsers.

IE 10+ Safari 6+

Also a framework for building applications with web components.

Polymer Extras

Web Animations

Pointer Events

Template Binding

Node.bind()

Model-driven Views (MDV)

Basic Polymer Element

<script src="polymer.js"></script>
<polymer-element name="my-element">
  <template>
    <h2>
      Hello, I'm a Polymer element
    </h2>
  </template>
  <script>Polymer("my-element");</script>
</polymer-element>
<!-- Ready to rock! -->
<my-element></my-element>

Attributes

<polymer-element name="fav-color" attributes="color">
  <template>
    <h2>My favorite color is: {{ color }}</h2>
  </template>
  <script>
    Polymer("fav-color", {
      color: "Orange"
    });
  </script>
</polymer-element>
<fav-color color="Purple"></fav-color>

Live Bindings

<polymer-element name="color-picker" attributes="color">
  <template>
    <p>My favorite color is
      <span style="background: {{ color }}">{{ color }}</span>
    </p>
    <input type="text" value="{{ color }}">
  </template>
  <script>
    Polymer("color-picker", { color: "Tomato" });
  </script>
</polymer-element>
!!! DO NOT TYPE ANYTHING !!!

Lifecycle Callbacks

created() When a new instance is created. Use like a constructor

enteredView() When an element is added to the page

leftView() When an element is removed from the page

attributeChanged(attrName, oldVal, newVal) When one of an element's attributes changes

There's moar!

Awesome Knowledges!

Web Components Resources

HTML5 Rocks

Polymer

X-Tags

Brick

CustomElements.io

Chromium Dashboard

Components Used in this Talk

Chart.js

Markdown

MailChimp

Google Analytics

Moment.js

Thanks!

Rob Dodson / @rob_dodson