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
350
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
Implementation Patterns
denyspoltorak
0
280
0→1 フロントエンド開発 Tips🚀 #レバテックMeetup
bengo4com
0
560
CSC307 Lecture 02
javiergs
PRO
1
780
AIによる高速開発をどう制御するか? ガードレール設置で開発速度と品質を両立させたチームの事例
tonkotsuboy_com
7
2.2k
15年続くIoTサービスのSREエンジニアが挑む分散トレーシング導入
melonps
2
190
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
CSC307 Lecture 06
javiergs
PRO
0
680
humanlayerのブログから学ぶ、良いCLAUDE.mdの書き方
tsukamoto1783
0
190
[KNOTS 2026登壇資料]AIで拡張‧交差する プロダクト開発のプロセス および携わるメンバーの役割
hisatake
0
270
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
1.8k
今から始めるClaude Code超入門
448jp
8
8.6k
フルサイクルエンジニアリングをAI Agentで全自動化したい 〜構想と現在地〜
kamina_zzz
0
400
Featured
See All Featured
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
140
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
0
320
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
0
200
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.4k
GitHub's CSS Performance
jonrohan
1032
470k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
61
52k
Making Projects Easy
brettharned
120
6.6k
The untapped power of vector embeddings
frankvandijk
1
1.6k
Automating Front-end Workflow
addyosmani
1371
200k
Done Done
chrislema
186
16k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
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