Upgrade to Pro — share decks privately, control downloads, hide ads and more …

When to use web components

When to use web components

My presentation at the FrontendDeveloperLove 2018 conference

Tim van der Lippe

February 16, 2018
Tweet

Other Decks in Programming

Transcript

  1. Dynamically creating DOM node.innerHTML = ` <header> TODOList: </header> <span>Presentation

    at: <a href="https://www.frontenddeveloperlove.com/" >FrontendDevelopersLove</a> </span> `
  2. 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);
  3. 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));
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. When to use Shadow DOM Encapsulate DOM to prevent taint

    by global CSS Hide implementation details Overusing Shadow DOM
  10. Team Parkour Research + prototype team Alex Russell Polymer Summit

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

    Summit 2017 https://www.youtube.com/watch?v=y-8Lmg5Gobw
  12. 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'); }
  13. 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);
  14. Angular React Vue ngOnInit constructor created ngAfterContentChecked componentDidMount mounted ngOnDestroy

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

    componentWillUnmount destroyed ngOnChanges componentDidUpdate updated Native constructor connectedCallback disconnectedCallback attributeChangedCallback
  16. Investigated improvements HTML & DOM JS CSS Custom Elements Classes

    CSS Variables <template> Promise Web animations Shadow DOM async/await
  17. 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>
  18. 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>
  19. 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>
  20. 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>
  21. 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
  22. 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);
  23. 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);
  24. 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);
  25. 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);
  26. 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);
  27. “And React's component based model was perfect for hiding all

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

    the implementation details in a component