Web Components

 

Use it or Lose it?

Sara HARKOUSSE

Duchess France

Paris, 17 Mai 2017

http://vignette2.wikia.nocookie.net/weirdcommunity/images/a/a2/Rainbow-flow-abstract-backgrounds-for-powerpoint.jpg/revision/latest?cb=20130603085532​​

SARA HARKOUSSE

@Sara_harkousse

 

 

Tech Lead, front-end Web developer at Dassault Systèmes

3D design & PLM software

 

"Duchess France" contributor & 3DS advocate at "Elles Bougent"

 

 

About me

#DuchessFrance2017

Motivation

  • Modular architecture

Filterable Product Table

Search Bar

Product Table

Product Row

Product Category Row

https://facebook.github.io/react/docs/thinking-in-react.html

#DuchessFrance2017 #webcomponents @Sara_harkousse

Angular 4.0 Component

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>`
})

export class AppComponent { name = 'Angular'; }
<my-app><h1>Hello Angular</h1></my-app>

https://embed.plnkr.co/?show=preview&show=app%2Fapp.component.ts

#DuchessFrance2017 #webcomponents @Sara_harkousse

Ember 2.12.0 Component

<article class="blog-post">
  <h1>{{title}}</h1>
  <p>{{yield}}</p>
  <p>Edit title: {{input type="text" value=title}}</p>
</article>
{{#each model as |post|}}
  {{#blog-post title=post.title}}
    {{post.body}}
  {{/blog-post}}
{{/each}}

https://guides.emberjs.com/v2.12.0/components/defining-a-component/

Polymer 2.0 Element

  // Define the class for a new element called custom-element
  class CustomElement extends Polymer.Element {
    static get is() { return "custom-element"; }
    constructor() {
        super();
        this.textContent = "I'm a custom-element.";
      }
  }
  // Register the new element with the browser
  customElements.define(CustomElement.is, CustomElement);
<custom-element></custom-element>

http://plnkr.co/edit/PaCt2M?p=preview

Frameworks make it hard to get along

#DuchessFrance2017 #webcomponents @Sara_harkousse

#DuchessFrance2017 #webcomponents @Sara_harkousse

Browser support

https://www.webcomponents.org/

  • use webcomponents.js

Refresher on web components

Web components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web apps.”

#DuchessFrance2017 #webcomponents @Sara_harkousse

https://www.webcomponents.org/

Refresher on web components

  • HTML Template Tag

  • HTML Imports

  • Custom Elements

  • Shadow DOM

#DuchessFrance2017 #webcomponents @Sara_harkousse

HTML Template Tag

  <template id="template">
    <div id="container">
      <img class="webcomponents" src="https://webcomponents/imgs/webcomponents-logo.svg">
    </div>
  </template>

https://jsfiddle.net/sara_harkousse/rnu8zc0c/

#DuchessFrance2017 #webcomponents @Sara_harkousse

HTML Template Tag Usage

var template = document.querySelector('#template');
var clone = document.importNode(template.content, true);
var host = document.querySelector('#host');
host.appendChild(clone);

https://jsfiddle.net/sara_harkousse/rnu8zc0c/

#DuchessFrance2017 #webcomponents @Sara_harkousse

HTML Template Tag

  • A way to add inert DOM elements to your document

  • Not something that's going to revolutionize your apps

  • No two-way data binding, no binding at all

#DuchessFrance2017 #webcomponents @Sara_harkousse

HTML Imports

 <link rel="import" href="/imports/productRow.html"> 
 <script src="js/productRow.js"></script> 
 <template> 
    <!-- content-->
 <template> 

#DuchessFrance2017 #webcomponents @Sara_harkousse

How to get my component?

var link = document.querySelector('link[rel="import"]');
var content = link.import;

// Grab DOM from productRow.html's document.
var el = content.querySelector('.productRow');
document.body.appendChild(el.cloneNode(true));

#DuchessFrance2017 #webcomponents @Sara_harkousse

Hammering our server

  • Each one of the HTML imports is another XMLHttpRequest

#DuchessFrance2017 #webcomponents @Sara_harkousse

Build tools for HTML Import

  • e.g. Vulcanizr (turns all imports into one import)

#DuchessFrance2017 #webcomponents @Sara_harkousse

HTML Import requires a polyfill

  • ES6 module?

https://www.webcomponents.org/

#DuchessFrance2017 #webcomponents @Sara_harkousse

Shadow DOM

  • A tiny document

  • exists inside of a host element

#DuchessFrance2017 #webcomponents @Sara_harkousse

Key concepts

  • Isolated DOM

  • Scoped CSS

#DuchessFrance2017 #webcomponents @Sara_harkousse

Shadow DOM requires a polyfill

  • Hard to polyfill

#DuchessFrance2017 #webcomponents @Sara_harkousse

Use/Don't use

Shadow DOM?

callback() {
    // Use it
    this.root = this.attachShadow({mode: 'open'});

    var template = document.querySelector('#template');
    var clone = document.importNode(template.content, true);
    this.root.appendChild(clone);
}

callback() {
    // Don't Use it
    this.root = this;

    var template = document.querySelector('#template');
    var clone = document.importNode(template.content, true);
    this.root.appendChild(clone);
}

#DuchessFrance2017 #webcomponents @Sara_harkousse

Use/Don't use

Shadow DOM?

/* Use it */
:host {
    color: red;
}

/* Don't use it */
custom-component {
    color: red;
}

#DuchessFrance2017 #webcomponents @Sara_harkousse

Use AND Don't use

Shadow DOM

if (shadowflag){
    this.root = this.attachShadow({mode: 'open'});
} else {
    this.root = this;
}
custom-component, :host {
    color: red;
}

#DuchessFrance2017 #webcomponents @Sara_harkousse

Custom Elements

class CustomButton extends HTMLElement {...}
window.customElements.define('custom-button', CustomButton);
<custom-button></custom-button>
  • Acts like a div

#DuchessFrance2017 #webcomponents @Sara_harkousse

Custom Elements

class CustomButton extends HTMLButtonElement {...}
window.customElements.define('custom-button', CustomButton, {extends: 'button'});
<button is="custom-button" disabled>My button!</button>
  • Acts like a real button

#DuchessFrance2017 #webcomponents @Sara_harkousse

Custom Elements ES6 Class

class custom-component extends HTMLElement {
  constructor() {
    super(); // always call super() first in the ctor.
    ...
  }
  connectedCallback() {
    ...
  }
  disconnectedCallback() {
    ...
  }
  attributeChangedCallback(attrName, oldVal, newVal) {
    ...
  }

}

#DuchessFrance2017 #webcomponents @Sara_harkousse

Component example

 Bootstrap Progress Bar

<div class="progress">
  <div class="progress-bar" style="width: 60%;">
    60%
  </div>
</div>

#DuchessFrance2017 #webcomponents @Sara_harkousse

window.customElements.define('progress-bar', ProgressBar);
// Use
<progress-bar></progress-bar>

Component example

#DuchessFrance2017 #webcomponents @Sara_harkousse

https://jsfiddle.net/sara_harkousse/kwwe75yy/

class ProgressBar extends HTMLElement { 
	
	constructor() { 
		super(); // always call super() first in the ctor.
		
		this.shadow = this.attachShadow({mode: 'open'});
		this._complete = 0;				
	}
	
	get complete() {
		return this._complete;
	}
	
	set complete(val) {
		this.setAttribute('complete', val);
	}	
	
	static get observedAttributes() {
		return ['complete'];
	}	

	attributeChangedCallback(name, oldval, newval) {
		var innerBar = this.shadow.querySelector('.progress-bar-inner');
		switch(name) {
			case 'complete':
				this._complete =  parseInt(newval, 10) || 0;
				innerBar.style.width = this.complete + '%';
				innerBar.innerHTML = this.complete + '%';
		}
	}
	
	connectedCallback() {
		var template = `<div class="progress-bar">
				    <div class="progress-bar-inner">${this.complete}%</div>
				</div>`; 
		this.shadow.innerHTML = template;
	}
}

Components on a page

<!doctype html>
<html lang="en">

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

    <body>
        <custom-navbar style="compact"></custom-navbar>
        <custom-toolbar style="full"></custom-toolbar>
        <custom-pagecontent>
            <custom-item attr="val"></custom-item>
            <custom-input attr="val"></custom-input>
            <progress-bar></progress-bar>
        </custom-pagecontent>

        <script>
            document.querySelector('progress-bar').addEventListener(
                'customevent', function () {
                    // do something
                 }
            });
        </script>
    </body>

</html>

#DuchessFrance2017 #webcomponents @Sara_harkousse

Takeaway

You will understand some of the design decisions of major frameworks if you learn about custom elements

#DuchessFrance2017 #webcomponents @Sara_harkousse

Takeaway

Who is using web components?

#DuchessFrance2017 #webcomponents @Sara_harkousse

Takeaway

GitHub

Mozilla VR

Google

#DuchessFrance2017 #webcomponents @Sara_harkousse

Thanks for listening!

Follow for slides

@Sara_harkousse

#DuchessFrance2017 #webcomponents

http://slides.com/sara_harkousse/web-components-talk-2#/

Made with Slides.com