Cory Brown

@uniqname

What Can Web Components Do For Me?

Questions?

  • Can I use them?

  • Why?

  • How?

  • Yes

  • Let me explain, no there is too much. Let me sum up.

  • We'll get to that.

Principles of Componitization

  • A single feature
  • Self-contained
  • Reusable.

Single Feature

Divide apps into problem spaces and group code around these problem spaces. Do not group around technology.

Self-contained

A component must not rely on the inferred existence of a particular state in the application. Any dependency should be provided to the component explicitly.

myElement.configurate = function (config) {
   let defaults = {
        some: 'thing'
    },
        settingsAttr = JSON.parse(
        myElement.getAttribute('settings')
    );


   let settings = _.extend({}, defaults, settingsAttr, config);
}
myElement.configurate = function (config) {
   let defaults = {
        some: 'thing'
    },
        settingsAttr = JSON.parse(
        myElement.getAttribute('settings')
    );


   let settings = Object.assign({}, defaults, settingsAttr, config);
}
myElement.configurate = function (config) {
   let defaults = {
        some: 'thing'
    },
        settingsAttr = myElement.getAttribute('settings') || '{}';

    try { settingsAttr = JSON.parse(settingsAttr); }
    catch(e) { settingsAttr = {}; }

   let settings = Object.assign({}, defaults, settingsAttr, config);
}

Reusable

In order to be reusable, a component must be:

  • Repeatable
  • Configurable
  • Extensible
  • Composable

Your code is not reusable if it fails any of these tests.

Repeatable

A component is repeatable if it is easy to create multiple instances of it.

'Instance' in this case does not need to carry with it all the bagage it noramlly does in an OOP context.

Configurable

A component is configurable if it can be easily appropriated for a given task.

Extensible

A component is extensible if additional functionality can be easily and unobtrusively added. This may be in the form of event hooks, lifecycle hooks or an extensibility api.

Composable

A component is composable if it can be easily combined with other components to create new, more complex ones.

Web Components: Proper

HTML Imports

Shadow DOM

HTML Templates

Custom Elements

HTML Imports

Shadow DOM

HTML Templates

Custom Elements

Polyfill All The Things!

HTML Imports 37K/8K gmin

Shadow DOM 160K/20K gmin

HTML Templates FREE .99

Custom Elements 33K/8K gmin

webcomponents.js 258K/37K gmin

webcomponents-lite.js 78K/16K gmin

Polyfill All The Things!

OMG
IKR
Totes cray!

Roll that beautiful web components footage!!!

HTML Imports

  • Include HTML in HTML (it's like HTML inception)
  • Package a component as a single consumable.
  • Handles dependency resolution
  • Handles cyclical dependencies.

 

  • Pairs well with HTTP/2
  • Less efficient over HTTP/1.1 without something like vulcanize

HTML Imports

<link rel="stylesheet" href="styles.css" />
<div class="class">
    Any valid HTML can go in an HTML Import file.
</div>
<script src="some-file.js"></script>

<link rel="import" href="/path/to/my/web-component.html" />

use it

create it

HTML Imports

HTML Imports

  • Replace the <link ="import" /> with a <script>
  • Create a template property on the component prototype
  • Assign said template property the value of a js generated template element who's contents is the template contents from the import

 

Living without

HTML Imports

Living without

Shadow DOM

  • Encapsulate structural implementations of UI (HTML)
  • Encapsulate component styles (prevent "leakage")
  • Prevent the external environment from accidentally accessing the internal one.
  • Provides a means of composition via a node distribution model

Shadow DOM

Many have seen ShadowDOM as a means of explaining aspects of how the web -- specifically HTML -- works.


<select>

<audio>/<video>

<details>

This is the summaryI'm a detail

Shadow DOM

let shadowHost = document.querySelector('#needsShadow'),
    shadowChild = document.createElement('p');

shadowHost.createShadowRoot();
shadowHost.shadowRoot.append(shadowChild);

Shadow DOM

Shadow DOM

just replace all references to `this.shadowRoot` with `this`.

Living without

Shadow DOM

Living without

HTML Templates

  • Content is effectively inert until activated
  • Content does not render in the page
  • Content is not considered part of the document
  • Content produces no side effects (scripts don't run, images don't load, audio doesn't play)
  • Template content is "activated" by deep cloning its `content` property -- a read-only documentFragment containing the parsed DOM of the template's contents.

HTML Templates

  • Does not have a concept of data binding.
  • Is not dynamic
  • It's just DOM

HTML Templates

HTML Templates are supported by every major evergreen browser.

It's ridiculously easy to polyfill*

*OK, it's more like a patch as the contents won't be inert, but it's better than writing code around it and we're coding for the future right? RIGHT?

HTML Templates

<template>

    <p>Any <strong>HTML</strong>.</p>

    <p>Seriously, <em>any</em> <abbr>HTML<abbr></p>

</template>

build it

HTML Templates

var el = document.querySelector(div),

    fragment = document.importNode(
        document.querySelector('template').content,
        true
    );

el.appendChild(fragment);

use it

HTML Templates

HTML Templates

  • create a `not-a-template` element
  • define a `content` property on it with a getter
  • return a DOM fragment of the `not-a-template`s innerHTML

Living without

HTML Templates

Custom Elements

Define Custom Semantic Elements as Components

React to lifecycle events

  • createdCallback
  • attachedCallback
  • detachedCallback
  • attributeChangedCallback

All other standard events are available to you.

Receive config through attributes (events?)

Expose information via custom events.

 

Custom Elements

This is where the real power is.

Lifecycle callbacks are RAD!*

*All though technically you don't even need this. Mutation Observers can be made to accomplish the same thing. In fact, this is how Custom Elements is polyfilled.

Custom Elements

const awesomePrototype = Object.create(HTMLElement, {

    // assign methods and properties
});

awesomePrototype.createdCallback = function () { ... };

awesomePrototype.attachedCallback = function () { ... };

awesomePrototype.detachedCallback = function () { ... };

awesomePrototype.attributeChangedCallback = function (attrName, prevVal, currVal) { ... };

document.registerElement('awe-some', {
    prototype: awesomePrototype
});

built it.

Custom Elements

<awe-some rad="SORT">
    <p>Composed DOM</p>
    <p>AKA Light DOM</p>
</awe-smome>

use it.

Custom Elements

const awesomePrototype = Object.create(HTMLElement, {

    rad: {
    
        get() {
            return this.getAttribute('rad');
        },
        set(val) {
            return this.setAttribute('rad', val);
        }

    }
});

document.registerElement('awe-some', {
    prototype: awesomePrototype
});

pro tip: bind attributes to properies with getters/setters.

Custom Elements

Thank You

(loud applause!)