#DevoxxFR

Sara Harkousse @Sara_harkousse

Web Components

It's all rainbows and unicorns! Is it?

SARA HARKOUSSE

@Sara_harkousse



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

Duchess France Leader





About me

#DevoxxFR #webcomponents

Web Components

 

It's all rainbows and unicorns! Is it?

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

Motivation

#DevoxxFR #webcomponents @Sara_harkousse

  • Modular architecture

Filterable Product Table

Search Bar

Product Table

Product Row

Product Category Row

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

Angular 5.2.10 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://angular.io/tutorial/toh-pt1

#DevoxxFR #webcomponents @Sara_harkousse

Ember 3.0.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/v3.0.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('custom-element', CustomElement);
<custom-element></custom-element>

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

#DevoxxFR #webcomponents @Sara_harkousse

Frameworks make it hard to get along

#DevoxxFR #webcomponents @Sara_harkousse

Harmony happens when there is less learning curve

Browser support

https://www.webcomponents.org/

  • use webcomponents.js

#DevoxxFR #webcomponents @Sara_harkousse

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.”

https://www.webcomponents.org/

#DevoxxFR #webcomponents @Sara_harkousse

Refresher on web components

#DevoxxFR #webcomponents @Sara_harkousse

  • HTML Template Tag

  • Shadow DOM

  • Custom Elements

  • HTML Imports

HTML Template Tag

#DevoxxFR #webcomponents @Sara_harkousse

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

https://github.com/SaraHarkousse/Web_Components/tree/master/VanillaJS/Template

HTML Template Tag Usage

#DevoxxFR #webcomponents @Sara_harkousse

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

https://github.com/SaraHarkousse/Web_Components/tree/master/VanillaJS/Template

HTML Template Tag

#DevoxxFR #webcomponents @Sara_harkousse

  • 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

HTML Template Tag Futur ?

#DevoxxFR #webcomponents @Sara_harkousse

#DevoxxFR #webcomponents @Sara_harkousse

Shadow DOM

  • A tiny document

  • exists inside of a host element

#DevoxxFR #webcomponents @Sara_harkousse

Shadow DOM requires a polyfill

  • Hard to polyfill

#DevoxxFR #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);
}

#DevoxxFR #webcomponents @Sara_harkousse

Use/Don't use

Shadow DOM?

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

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

#DevoxxFR #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;
}

#DevoxxFR #webcomponents @Sara_harkousse

Custom Elements

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

#DevoxxFR #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

#DevoxxFR #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) {
    ...
  }

}

HTML Imports

#DevoxxFR #webcomponents @Sara_harkousse

 <link rel="import" href="component.html"> 
 <link rel="stylesheet" href="style.css"> 
 <div id="container">
     <img class="rotate" src="logo.svg">
 </div>
 <script src="script.js"></script>

How to get my component?

#DevoxxFR #webcomponents @Sara_harkousse

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

// Grab DOM from component.html's document.
var el = content.querySelector('#container');
var clone = el.cloneNode(true);
var host = document.querySelector('#host');
host.appendChild(clone);

#DevoxxFR #webcomponents @Sara_harkousse

HTML Import requires a polyfill

  • ES module?

https://www.webcomponents.org/

#DevoxxFR #webcomponents @Sara_harkousse

ES module

// export feature
export const Component = // … 

// import feature
import {Component} from '../components/cutom-component.js';

#DevoxxFR #webcomponents @Sara_harkousse

Components on a page

<!doctype html>
<html lang="en">
    <head>
        <link rel="import" href="/components/CustomNavbar.html">
        ..
    </head>
    <body>
        <custom-navbar style="compact"></custom-navbar>
        <custom-toolbar style="full"></custom-toolbar>
        <custom-pagecontent>
            <custom-input attr="val"></custom-input>
            <progress-bar></progress-bar>
        </custom-pagecontent>

        <script>
            ...
        </script>
    </body>
</html>

#DevoxxFR #webcomponents @Sara_harkousse

Communication between Components on a page

<script>
    document.querySelector('custom-input').dispatchEvent(new CustomEvent('customevent', {
        detail: { prop: true }
    }));
    
    customElements.whenDefined('progress-bar').then(() => {
        document.querySelector('progress-bar').addEventListener(
            'customevent', function () {
                 // do something
             }
        });
    });
</script>

#DevoxxFR #webcomponents @Sara_harkousse

Takeaway

  • Template tag? yeah! why not?

  • Use ES module instead of HTML Imports

  • Use Shadom DOM with a flag

  • Custom Elements?? Go, Go, Go

 

#DevoxxFR #webcomponents

Thanks for listening!

Follow for slides

@Sara_harkousse

https://github.com/SaraHarkousse

https://www.programmez.com/magazine/article/web-components-que-du-bonheur-nest-ce-pas

Made with Slides.com