Slide 1

Slide 1 text

When to use web components Tim van der Lippe TimvdLippe

Slide 2

Slide 2 text

Remote Polymer team member Master student Computer Science Delft University of Technology

Slide 3

Slide 3 text

3 accepted standards

Slide 4

Slide 4 text

Schedule Accepted standards ● ● Shadow DOM ● Custom Elements Examples

Slide 5

Slide 5 text

element

Slide 6

Slide 6 text

Blueprint TODOList: Presentation at: FrontendDevelopersLove

Slide 7

Slide 7 text

Dynamically creating DOM

Slide 8

Slide 8 text

Dynamically creating DOM node.innerHTML = ` TODOList: Presentation at: FrontendDevelopersLove `

Slide 9

Slide 9 text

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);

Slide 10

Slide 10 text

Performance problems Parsing (innerHTML)

Slide 11

Slide 11 text

Performance problems Creation of JS nodes (document.createElement)

Slide 12

Slide 12 text

Performance problems DOM manipulation (all)

Slide 13

Slide 13 text

Dynamically creating DOM const template = document.createElement('template'); template.innerHTML = ` TODOList: Presentation at: FrontendDevelopersLove `; node.appendChild(template.content.cloneNode(true));

Slide 14

Slide 14 text

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%

Slide 15

Slide 15 text

When to use 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

Slide 16

Slide 16 text

Shadow DOM

Slide 17

Slide 17 text

Native elements have encapsulation http://techslides.com/demos/sample-videos/small.mp4

Slide 18

Slide 18 text

Native elements have encapsulation http://techslides.com/demos/sample-videos/small.mp4

Slide 19

Slide 19 text

Native elements have encapsulation CSS rules do not reach into shadow DOM Hide implementation details

Slide 20

Slide 20 text

CSS scoping/encapsulation Naming convention (BEM)

Slide 21

Slide 21 text

CSS scoping/encapsulation Runtime class generation (styled-components)

Slide 22

Slide 22 text

CSS scoping/encapsulation None (and pray)

Slide 23

Slide 23 text

User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML = ` span { color: red; } In Shadow DOM` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow

Slide 24

Slide 24 text

User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML = ` span { color: red; } In Shadow DOM` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow

Slide 25

Slide 25 text

User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML = ` span { color: red; } In Shadow DOM` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow

Slide 26

Slide 26 text

User-exposed Shadow DOM const div = document.createElement('div'); div.attachShadow({mode: 'open'}); div.shadowRoot.innerHTML = ` span { color: red; } In Shadow DOM` document.body.appendChild(div); https://dom.spec.whatwg.org/#dom-element-attachshadow

Slide 27

Slide 27 text

Other (implementation) benefits Cheap style invariance checks Simple CSS selectors

Slide 28

Slide 28 text

When to use Shadow DOM Encapsulate DOM to prevent taint by global CSS Hide implementation details Overusing Shadow DOM

Slide 29

Slide 29 text

Custom Elements

Slide 30

Slide 30 text

Team Parkour Research + prototype team Alex Russell Polymer Summit 2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw

Slide 31

Slide 31 text

Team Parkour State-of-the-art back then Alex Russell Polymer Summit 2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw

Slide 32

Slide 32 text

Team Parkour Identify areas that are common Alex Russell Polymer Summit 2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw

Slide 33

Slide 33 text

Component model $.widget('ui.menu', { defaultElement: '
    ', options: { role: 'menu' }, _create: function() { this.activeMenu = this.element; this._addClass('ui-menu', 'ui-widget ui-widget-content'); }

Slide 34

Slide 34 text

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);

Slide 35

Slide 35 text

Dojo dojo.declare('dijit.MenuItem' [dijit._Widget, dijit._Templated, dijit._Contained], { // Summary: A line item in a Menu Widget } )

Slide 36

Slide 36 text

Angular React Vue ngOnInit constructor created ngAfterContentChecked componentDidMount mounted ngOnDestroy componentWillUnmount destroyed ngOnChanges componentDidUpdate updated

Slide 37

Slide 37 text

Angular React Vue ngOnInit constructor created ngAfterContentChecked componentDidMount mounted ngOnDestroy componentWillUnmount destroyed ngOnChanges componentDidUpdate updated Native constructor connectedCallback disconnectedCallback attributeChangedCallback

Slide 38

Slide 38 text

https://xkcd.com/927/

Slide 39

Slide 39 text

Investigated improvements HTML & DOM JS CSS Custom Elements Classes CSS Variables Promise Web animations Shadow DOM async/await

Slide 40

Slide 40 text

Browser standards ● ●

Slide 41

Slide 41 text

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);

Slide 42

Slide 42 text

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);

Slide 43

Slide 43 text

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);

Slide 44

Slide 44 text

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);

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Combine together

Slide 47

Slide 47 text

Slide 48

Slide 48 text

const template = document.createElement('template'); template.innerHTML = ` img { border-radius: 50%; } `; 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);

Slide 49

Slide 49 text

const template = document.createElement('template'); template.innerHTML = ` img { border-radius: 50%; } `; 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);

Slide 50

Slide 50 text

const template = document.createElement('template'); template.innerHTML = ` img { border-radius: 50%; } `; 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);

Slide 51

Slide 51 text

const template = document.createElement('template'); template.innerHTML = ` img { border-radius: 50%; } `; 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);

Slide 52

Slide 52 text

const template = document.createElement('template'); template.innerHTML = ` img { border-radius: 50%; } `; 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);

Slide 53

Slide 53 text

Webcomponent libraries

Slide 54

Slide 54 text

https://timvdlippe.github.io/react-imgpro/ Based on https://github.com/nitin42/react-imgpro

Slide 55

Slide 55 text

“And React's component based model was perfect for hiding all the implementation details in a component”

Slide 56

Slide 56 text

And Web component based model was perfect for hiding all the implementation details in a component

Slide 57

Slide 57 text

Straightforward translation componentDidMount connectedCallback JSX defaultProps observedAttributes

Slide 58

Slide 58 text

Conclusion

Slide 59

Slide 59 text

We talked about Shadow DOM Custom Elements

Slide 60

Slide 60 text

Interoperability

Slide 61

Slide 61 text

When to use web components Shadow DOM Custom Elements TimvdLippe