Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
When to use web components
Search
Tim van der Lippe
February 16, 2018
Programming
3
310
When to use web components
My presentation at the FrontendDeveloperLove 2018 conference
Tim van der Lippe
February 16, 2018
Tweet
Share
Other Decks in Programming
See All in Programming
Java 22 Overview
kishida
1
200
大規模UIKitベースアプリへのTCAの段階的導入/gradual-adoption-of-tca-in-a-large-scale-uikit-based-app
takehilo
2
210
PHPはいつから死んでいるかの調査
chiroruxx
2
420
CREってこういうこと? 体験入社 - 提案資料 - / what-is-cre-trial-employment
shinden
1
550
Komplexe Oberflächen mit SVG und der Web Animation API
joergneumann
0
680
禅の心を手に入れよ
eltociear
1
410
OpenAPIを中心に考えるAPI開発入門 / Introduction to API Development with a Focus on OpenAPI
seike460
PRO
2
180
Direct Style Effect Systems The Print[A] ExampleA Comprehension Aid
philipschwarz
PRO
0
150
パフォーマンスを求めてDBに機能を寄せる戦略
aoyagikouhei
0
110
Scalable Customer Journey Orchestration (CJO)
lewuathe
0
440
MicrosoftのPlatform Engineeringガイドを読んで実際になにかやってみた
ymd65536
1
520
Goのエラースタックトレースの歴史と今後
sonatard
10
1.8k
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
41
4.4k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
34
6k
No one is an island. Learnings from fostering a developers community.
thoeni
16
2.1k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
126
32k
Debugging Ruby Performance
tmm1
70
11k
A Philosophy of Restraint
colly
197
16k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
155
14k
Producing Creativity
orderedlist
PRO
338
39k
Raft: Consensus for Rubyists
vanstee
133
6.3k
Six Lessons from altMBA
skipperchong
22
3k
Infographics Made Easy
chrislema
238
18k
Making the Leap to Tech Lead
cromwellryan
125
8.5k
Transcript
When to use web components Tim van der Lippe TimvdLippe
Remote Polymer team member Master student Computer Science Delft University
of Technology
3 accepted standards
Schedule Accepted standards • <template> • Shadow DOM • Custom
Elements Examples
<template> element
Blueprint <template> <header> TODOList: </header> <span>Presentation at: <a href="https://www.frontenddeveloperlove.com/" >FrontendDevelopersLove</a>
</span> </template>
Dynamically creating DOM
Dynamically creating DOM node.innerHTML = ` <header> TODOList: </header> <span>Presentation
at: <a href="https://www.frontenddeveloperlove.com/" >FrontendDevelopersLove</a> </span> `
Dynamically creating DOM const header = document.createElement('header'); header.innerText = `TODOList`;
const span = document.createElement('span'); const a = document.createElement('a'); a.href = `https://www.frontenddeveloperlove.com/`; a.innerText = `FrontendDevelopersLove`; span.appendChild(document.createTextNode('Presentation at:')) span.appendChild(a) node.appendChild(header); node.appendChild(span);
Performance problems Parsing (innerHTML)
Performance problems Creation of JS nodes (document.createElement)
Performance problems DOM manipulation (all)
Dynamically creating DOM const template = document.createElement('template'); template.innerHTML = `
<header> TODOList: </header> <span>Presentation at: <a href="https://www.frontenddeveloperlove.com/" >FrontendDevelopersLove</a> </span>`; node.appendChild(template.content.cloneNode(true));
https://jsperf.com/clonenode-vs-createelement-performance/95 Method Ops/sec Relative speed innerHTML 22,828 32% createElement 31,566
45% createElement (abstraction) 25,440 36% template.content.cloneNode 69,874 100%
When to use <template> Creating DOM based on the same
“template” (e.g. component) Efficiently update DOM after the fact (lit-html) Only creating DOM once “template” only consists of dynamic parts
Shadow DOM
Native elements have encapsulation http://techslides.com/demos/sample-videos/small.mp4
Native elements have encapsulation http://techslides.com/demos/sample-videos/small.mp4
Native elements have encapsulation CSS rules do not reach into
shadow DOM Hide implementation details
CSS scoping/encapsulation Naming convention (BEM)
CSS scoping/encapsulation Runtime class generation (styled-components)
CSS scoping/encapsulation None (and pray)
User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML
= ` <style> span { color: red; } </style> <span>In Shadow DOM</span>` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow
User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML
= ` <style> span { color: red; } </style> <span>In Shadow DOM</span>` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow
User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML
= ` <style> span { color: red; } </style> <span>In Shadow DOM</span>` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow
User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML
= ` <style> span { color: red; } </style> <span>In Shadow DOM</span>` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow
Other (implementation) benefits Cheap style invariance checks Simple CSS selectors
When to use Shadow DOM Encapsulate DOM to prevent taint
by global CSS Hide implementation details Overusing Shadow DOM
Custom Elements
Team Parkour Research + prototype team Alex Russell Polymer Summit
2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw
Team Parkour State-of-the-art back then Alex Russell Polymer Summit 2017
https://www.youtube.com/watch?v=y-8Lmg5Gobw
Team Parkour Identify areas that are common Alex Russell Polymer
Summit 2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw
Component model $.widget('ui.menu', { defaultElement: '<ul>', options: { role: 'menu'
}, _create: function() { this.activeMenu = this.element; this._addClass('ui-menu', 'ui-widget ui-widget-content'); }
Component model goog.ui.MenuItem = function(content, opt_model, opt_domHelper, opt_renderer) { goog.ui.Control.call(
this, content, opt_renderer || goog.ui.MenuItemRenderer.getInstance(), opt_domHelper) this.setValue(opt_model); } goog.inherits(goog.ui.MenuItem, goog.ui.Control);
Dojo dojo.declare('dijit.MenuItem' [dijit._Widget, dijit._Templated, dijit._Contained], { // Summary: A line
item in a Menu Widget } )
Angular React Vue ngOnInit constructor created ngAfterContentChecked componentDidMount mounted ngOnDestroy
componentWillUnmount destroyed ngOnChanges componentDidUpdate updated
Angular React Vue ngOnInit constructor created ngAfterContentChecked componentDidMount mounted ngOnDestroy
componentWillUnmount destroyed ngOnChanges componentDidUpdate updated Native constructor connectedCallback disconnectedCallback attributeChangedCallback
https://xkcd.com/927/
Investigated improvements HTML & DOM JS CSS Custom Elements Classes
CSS Variables <template> Promise Web animations Shadow DOM async/await
Browser standards • •
class HelloWorld extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = 'Hello World!'; } connectedCallback() { console.log('connected!'); } disconnectedCallback() { console.log('disconnected'); } }; customElements.define('hello-world', HelloWorld); <hello-world> </hello-world>
class HelloWorld extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = 'Hello World!'; } connectedCallback() { console.log('connected!'); } disconnectedCallback() { console.log('disconnected'); } }; customElements.define('hello-world', HelloWorld); <hello-world> </hello-world>
class HelloWorld extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = 'Hello World!'; } connectedCallback() { console.log('connected!'); } disconnectedCallback() { console.log('disconnected'); } }; customElements.define('hello-world', HelloWorld); <hello-world> </hello-world>
class HelloWorld extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = 'Hello World!'; } connectedCallback() { console.log('connected!'); } disconnectedCallback() { console.log('disconnected'); } }; customElements.define('hello-world', HelloWorld); <hello-world> </hello-world>
When to use Custom Elements Components on the web (without
libraries) Base layer for library authors Interoperability between components Solutions that do not require a component
Combine together
<profile-picture picture="TimvdLippe"> </profile-picture>
const template = document.createElement('template'); template.innerHTML = ` <style>img { border-radius:
50%; }</style> <img src="domain.com/fallback.png" /> `; class ProfilePicture extends HTMLElement{ constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this._image = this.shadowRoot.querySelector('img'); } static get observedAttributes() { return ['picture']; } attributeChangedCallback(name, oldValue, newValue) { this._image.src = `domain.com/${newValue}.png`; } } customElements.define('profile-picture', ProfilePicture);
const template = document.createElement('template'); template.innerHTML = ` <style>img { border-radius:
50%; }</style> <img src="domain.com/fallback.png" /> `; class ProfilePicture extends HTMLElement{ constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this._image = this.shadowRoot.querySelector('img'); } static get observedAttributes() { return ['picture']; } attributeChangedCallback(name, oldValue, newValue) { this._image.src = `domain.com/${newValue}.png`; } } customElements.define('profile-picture', ProfilePicture);
const template = document.createElement('template'); template.innerHTML = ` <style>img { border-radius:
50%; }</style> <img src="domain.com/fallback.png" /> `; class ProfilePicture extends HTMLElement{ constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this._image = this.shadowRoot.querySelector('img'); } static get observedAttributes() { return ['picture']; } attributeChangedCallback(name, oldValue, newValue) { this._image.src = `domain.com/${newValue}.png`; } } customElements.define('profile-picture', ProfilePicture);
const template = document.createElement('template'); template.innerHTML = ` <style>img { border-radius:
50%; }</style> <img src="domain.com/fallback.png" /> `; class ProfilePicture extends HTMLElement{ constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this._image = this.shadowRoot.querySelector('img'); } static get observedAttributes() { return ['picture']; } attributeChangedCallback(name, oldValue, newValue) { this._image.src = `domain.com/${newValue}.png`; } } customElements.define('profile-picture', ProfilePicture);
const template = document.createElement('template'); template.innerHTML = ` <style>img { border-radius:
50%; }</style> <img src="domain.com/fallback.png" /> `; class ProfilePicture extends HTMLElement{ constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(template.content.cloneNode(true)); this._image = this.shadowRoot.querySelector('img'); } static get observedAttributes() { return ['picture']; } attributeChangedCallback(name, oldValue, newValue) { this._image.src = `domain.com/${newValue}.png`; } } customElements.define('profile-picture', ProfilePicture);
Webcomponent libraries
https://timvdlippe.github.io/react-imgpro/ Based on https://github.com/nitin42/react-imgpro
“And React's component based model was perfect for hiding all
the implementation details in a component”
And Web component based model was perfect for hiding all
the implementation details in a component
Straightforward translation componentDidMount connectedCallback JSX <template> defaultProps observedAttributes
Conclusion
We talked about <template> Shadow DOM Custom Elements
Interoperability
When to use web components <template> Shadow DOM Custom Elements
TimvdLippe