Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Felix Arntz / WordCamp London 2019
Web Components
Introduction to
Web Components are a standardized set of browser
APIs that allow you to define your own HTML tags,
reusable and self-conta...
<p>Hovering <a href="#tooltip1" class="tooltip-source">this text</a> will display a tooltip.</p>
<div id="tooltip1" class=...
Example: Tooltips
<my-tooltips>
<p>Hovering <my-tooltip-anchor target="#tooltip1">this text</my-tooltip-anchor> will displ...
Benefits of Web Components
MaintainabilityReusability Encapsulation Standardization
React vs. Vue vs. Web Components
React Vue Web Components
const { Component } = React;
class MyComponent extends
Component...
Standardized Leaf Components
const { Component } = React;
class MyComponent extends Component {
render() {
const { active ...
https://youtu.be/plt-iH_47GE
Source: https://softwareengineeringdaily.com/2018/10/22/google-javascript-with-malte-ubl/
Many frameworks are modeled arou...
Shadow DOM
Allows style and markup
to be encapsulated from
the regular DOM.
Custom Elements
Allows developers to
define the...
Current Browser Support
See full browser support
caniuse.com/#feat=custom-elementsv1
caniuse.com/#feat=shadowdomv1
caniuse...
Let’s build a demo!
<h2 class="nav-tab-wrapper">
<a class="nav-tab nav-tab-active" href="#tab1">
Introduction
</a>
<a class="nav-tab" href="#t...
● wcig-tab for a single tab
● wcig-tab-panel for a single panel
associated with a tab
● wcig-tabs for the overall wrapper
...
Custom Elements
https://html.spec.whatwg.org/#custom-elements
The Custom Elements API
1. Create a class that extends HTMLElement
2. Implement the element’s behavior and style in that c...
class Tab extends HTMLElement {
constructor() {
super();
// ...
}
static get is() {
return 'wcig-tab';
}
static get observ...
connectedCallback() {
if ( ! this.hasAttribute( 'role' ) ) {
this.setAttribute( 'role', 'tab' );
}
const isSelected = this...
_onClick() {
if ( this.disabled || this.selected ) {
return;
}
this.selected = true;
this.dispatchEvent(
new CustomEvent(
...
static get observedAttributes() {
return [ 'selected', 'disabled' ];
}
attributeChangedCallback( name, oldValue, newValue ...
class Tab extends HTMLElement {
// ...
get selected() {
return this.hasAttribute( 'selected' );
}
set selected( val ) {
co...
class Tab extends HTMLElement {
// ...
}
customElements.define( Tab.is, Tab );
Registering The Custom Element
Shadow DOM
https://dom.spec.whatwg.org/#shadow-trees
What is the Shadow DOM?
● In addition to regular DOM node children, an element can have a
separate shadow tree attached to...
Example: The Built-in Range Input
Shadow trees have been used for quite a while by browsers already!
Providing Scoped Styles and Markup
class Tab extends HTMLElement {
constructor() {
super();
this.attachShadow( { mode: 'op...
HTML Templates
https://html.spec.whatwg.org/#the-template-element
The template Element
<template id="my-template">
<div id="element-from-template">
<p>Element content.</p>
</div>
</templat...
Improving Performance with a Template
const template = document.createElement( 'template' );
template.innerHTML = `
<style...
To Be Continued...
Look up the full codebase at
github.com/felixarntz/web-components-in-gutenberg
Further Reading
● https://developers.google.com/web/fundamentals/web-components/customelements
● https://developers.google...
Proprietary + Confidential
Web Components Projects
https://www.webcomponents.org
https://www.polymer-project.org
https://amp.dev
https://amp-wp.org
https://github.com/felixarntz/web-components-in-gutenberg
Get Started with Web Components
MaintainabilityReusability Encapsulation Standardization
Proprietary + Confidential
Thank You
Felix Arntz
@felixarntz
Introduction to Web Components
Introduction to Web Components
Upcoming SlideShare
Loading in …5
×

Introduction to Web Components

5 views

Published on

Originally presented at WordCamp London 2019

Published in: Internet
  • Be the first to comment

  • Be the first to like this

Introduction to Web Components

  1. 1. Felix Arntz / WordCamp London 2019 Web Components Introduction to
  2. 2. Web Components are a standardized set of browser APIs that allow you to define your own HTML tags, reusable and self-contained.
  3. 3. <p>Hovering <a href="#tooltip1" class="tooltip-source">this text</a> will display a tooltip.</p> <div id="tooltip1" class="tooltip"> <span class="tooltip-nag"></span> This is the tooltip content. </div> <style> .tooltip { position: absolute; display: none; max-width: 16rem; } /* many more style rules... */ </style> <script> document.querySelector( '.tooltip-source' ).addEventListener( 'hover', event => { event.preventDefault(); /* lots and lots more JavaScript... */ } ); </script> Example: Tooltips
  4. 4. Example: Tooltips <my-tooltips> <p>Hovering <my-tooltip-anchor target="#tooltip1">this text</my-tooltip-anchor> will display a tooltip.</p> <my-tooltip id="tooltip1"> This is the tooltip content. </my-tooltip> </my-tooltips>
  5. 5. Benefits of Web Components MaintainabilityReusability Encapsulation Standardization
  6. 6. React vs. Vue vs. Web Components React Vue Web Components const { Component } = React; class MyComponent extends Component { … } Vue.component( ‘my-component’, { … } ); class MyComponent extends HTMLElement { … } customElements.define( ‘my-component’, MyComponent ); <MyComponent></MyComponent> <my-component></my-component> <my-component></my-component> JSX (pre-processing required) HTML templates HTML templates Framework Framework Standard Key Takeaway: This is an unfair and false comparison.
  7. 7. Standardized Leaf Components const { Component } = React; class MyComponent extends Component { render() { const { active } = this.props; return ( <my-leaf-component active={ active }> </my-leaf-component> ); } } class MyLeafComponent extends HTMLElement { static get is() { return 'my-leaf-component'; } static get observedAttributes() { return [ 'active' ]; } } customElements.define( MyLeafComponent.is, MyLeafComponent ); React ❤ Web Components!
  8. 8. https://youtu.be/plt-iH_47GE
  9. 9. Source: https://softwareengineeringdaily.com/2018/10/22/google-javascript-with-malte-ubl/ Many frameworks are modeled around some notion of components. [...] So there's one thing that I am very sure of, which is that we will see Web Components as the basically only technology used for what I would call leaf components. Malte Ubl “ ”Tech Lead of the AMP Project
  10. 10. Shadow DOM Allows style and markup to be encapsulated from the regular DOM. Custom Elements Allows developers to define their own HTML tags. HTML Templates Allows to place markup in a page that is only parsed once necessary. Key Web APIs
  11. 11. Current Browser Support See full browser support caniuse.com/#feat=custom-elementsv1 caniuse.com/#feat=shadowdomv1 caniuse.com/#feat=template Also, check out the polyfill! (github.com/webcomponents/custom-elements)
  12. 12. Let’s build a demo!
  13. 13. <h2 class="nav-tab-wrapper"> <a class="nav-tab nav-tab-active" href="#tab1"> Introduction </a> <a class="nav-tab" href="#tab2"> Polymer </a> <!-- ... --> </h2> <div id="tab1" class="nav-tab-panel nav-tab-panel-active"><!-- Panel 1 content. --></div> <div id="tab2" class="nav-tab-panel"><!-- Panel 2 content. --></div> <!-- ... --> <h2 class="nav-tab-wrapper" role="tablist"> <a class="nav-tab nav-tab-active" href="#tab1" aria-controls="tab1" aria-selected="true" role="tab"> Introduction </a> <a class="nav-tab" href="#tab2" aria-controls="tab2" aria-selected="false" tabindex="-1" role="tab"> Polymer </a> <!-- ... --> </h2> <div id="tab1" class="nav-tab-panel nav-tab-panel-active" role="tabpanel"><!-- Panel 1 content. --></div> <div id="tab2" class="nav-tab-panel" aria-hidden="true" role="tabpanel"><!-- Panel 2 content. --></div> <!-- ... --> Typical WordPress Approach
  14. 14. ● wcig-tab for a single tab ● wcig-tab-panel for a single panel associated with a tab ● wcig-tabs for the overall wrapper Three Custom Elements <wcig-tabs> <wcig-tab slot="tabs" href="#tab1" selected> Introduction </wcig-tab> <wcig-tab-panel slot="tabpanels" id="tab1" active> <!-- Panel 1 content. --> </wcig-tab-panel> <wcig-tab slot="tabs" href="#tab2"> Polymer </wcig-tab> <wcig-tab-panel slot="tabpanels" id="tab2"> <!-- Panel 2 content. --> </wcig-tab-panel> <!-- ... --> </wcig-tabs>
  15. 15. Custom Elements https://html.spec.whatwg.org/#custom-elements
  16. 16. The Custom Elements API 1. Create a class that extends HTMLElement 2. Implement the element’s behavior and style in that class 3. Register the element with customElements.define( tagName, elementClass )
  17. 17. class Tab extends HTMLElement { constructor() { super(); // ... } static get is() { return 'wcig-tab'; } static get observedAttributes() { // ... } attributeChangedCallback( name, oldValue, newValue ) { // ... } connectedCallback() { // ... } disconnectedCallback() { // ... } } Scaffolding our Tab Element
  18. 18. connectedCallback() { if ( ! this.hasAttribute( 'role' ) ) { this.setAttribute( 'role', 'tab' ); } const isSelected = this.hasAttribute( 'selected' ); if ( ! this.hasAttribute( 'tabindex' ) ) { this.setAttribute( 'tabindex', isSelected ? 0 : -1 ); } if ( ! this.hasAttribute( 'aria-selected' ) ) { this.setAttribute( 'aria-selected', isSelected ? 'true' : 'false' ); } this.addEventListener( 'click', this._onClick ); } disconnectedCallback() { this.removeEventListener( 'click', this._onClick ); } Handling Custom Markup and Events
  19. 19. _onClick() { if ( this.disabled || this.selected ) { return; } this.selected = true; this.dispatchEvent( new CustomEvent( 'select', { bubbles: true } ) ); } Emitting a Tab Selection Event
  20. 20. static get observedAttributes() { return [ 'selected', 'disabled' ]; } attributeChangedCallback( name, oldValue, newValue ) { switch ( name ) { case 'selected': this.setAttribute( 'tabindex', null !== newValue ? 0 : -1 ); this.setAttribute( 'aria-selected', null !== newValue ? 'true' : 'false' ); break; case 'disabled': this.setAttribute( 'aria-disabled', null !== newValue ? 'true' : 'false' ); if ( null !== newValue || ! this.selected ) { this.removeAttribute( 'tabindex' ); this.blur(); } else { this.setAttribute( 'tabindex', 0 ); } break; } } Reacting to Attribute Changes
  21. 21. class Tab extends HTMLElement { // ... get selected() { return this.hasAttribute( 'selected' ); } set selected( val ) { const isSelected = Boolean( val ); if ( isSelected ) { this.setAttribute( 'selected', '' ); } else { this.removeAttribute( 'selected' ); } } } Reflecting Properties to Attributes const tab = document.createElement( 'wcig-tab' ); tab.selected = true; <wcig-tab selected></wcig-tab>
  22. 22. class Tab extends HTMLElement { // ... } customElements.define( Tab.is, Tab ); Registering The Custom Element
  23. 23. Shadow DOM https://dom.spec.whatwg.org/#shadow-trees
  24. 24. What is the Shadow DOM? ● In addition to regular DOM node children, an element can have a separate shadow tree attached to it. ● The element the shadow tree is attached to is called the shadow host. ● The document fragment attached to the shadow host is called the shadow root. ● Elements in the shadow tree are scoped to the shadow host element and cannot be accessed from the outside.
  25. 25. Example: The Built-in Range Input Shadow trees have been used for quite a while by browsers already!
  26. 26. Providing Scoped Styles and Markup class Tab extends HTMLElement { constructor() { super(); this.attachShadow( { mode: 'open' } ); this.shadowRoot.innerHTML = ` <style> :host { display: block; /* ... */ } :host(:focus), :host(:hover) { /* ... */ } :host([selected]) { /* ... */ } </style> <slot></slot> `; } // ... }
  27. 27. HTML Templates https://html.spec.whatwg.org/#the-template-element
  28. 28. The template Element <template id="my-template"> <div id="element-from-template"> <p>Element content.</p> </div> </template> const template = document.querySelector( '#my-template' ); const element = template.content.cloneNode( true );
  29. 29. Improving Performance with a Template const template = document.createElement( 'template' ); template.innerHTML = ` <style> :host { display: block; /* ... */ } /* ... */ </style> <slot></slot> `; class Tab extends HTMLElement { constructor() { super(); this.attachShadow( { mode: 'open' } ); this.shadowRoot.appendChild( template.content.cloneNode( true ) ); } // ... }
  30. 30. To Be Continued... Look up the full codebase at github.com/felixarntz/web-components-in-gutenberg
  31. 31. Further Reading ● https://developers.google.com/web/fundamentals/web-components/customelements ● https://developers.google.com/web/fundamentals/web-components/shadowdom ● https://developers.google.com/web/fundamentals/web-components/best-practices ● https://developers.google.com/web/fundamentals/primers/async-functions ● https://developers.google.com/web/fundamentals/primers/modules ● https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals ● https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set ● https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
  32. 32. Proprietary + Confidential Web Components Projects
  33. 33. https://www.webcomponents.org
  34. 34. https://www.polymer-project.org
  35. 35. https://amp.dev https://amp-wp.org
  36. 36. https://github.com/felixarntz/web-components-in-gutenberg
  37. 37. Get Started with Web Components MaintainabilityReusability Encapsulation Standardization
  38. 38. Proprietary + Confidential Thank You Felix Arntz @felixarntz

×