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

React Alicante '18 - 2018 - The Year of Web Components

React Alicante '18 - 2018 - The Year of Web Components

Talk about web components given at React Alicante in 2018. Example code:
github.com/dkundel/emoji-rating
github.com/dkundel/vote-my-talk-react

Dominik Kundel

September 14, 2018
Tweet

More Decks by Dominik Kundel

Other Decks in Programming

Transcript

  1. ! The dream <date-picker> </date-picker> <video> </video> <input type="text" />

    Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  2. Hi! I'm Dominik Kundel! Developer Evangelist at ! dkundel.com "

    @dkundel # [email protected] $ github/dkundel Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  3. ! " How do you share UI between projects? Dominik

    Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  4. Approach ! The "Bootstrap" approach Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  5. Approach 1: "Bootstrap" approach <!-- Bootstrap CSS --> <link rel="stylesheet"

    href="https: //maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https: //code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"> </script> <script src="https: //cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"> </script> <script src="https: //maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"> </script> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  6. Approach 1: "Bootstrap" approach <div class="alert alert-success" role="alert"> <h4 class="alert-heading">Well

    done! </h4> <p>Aww yeah, you successfully read this important alert message </p> <hr> <p class="mb-0"> Whenever you need to, be sure to use margin utilities to keep things nice and tidy. </p> </div> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  7. Approach ! The JavaScript API Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  8. Approach 2: JavaScript API <div id="map"> </div> <script> var map;

    function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: {lat: -34.397, lng: 150.644}, zoom: 8 }); } </script> <script src="https: //maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer> </script> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  9. Approach ! "Share button" style Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  10. Approach 3: "Share button" style <div id="fb-root"> </div> <script>(function(d, s,

    id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = 'https: //connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.12&appId=APP_ID&autoLogAppEvents=1'; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); </script> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  11. Approach 3: "Share button" style <div class="fb-share-button" data-href="https: //developers.facebook.com/docs/plugins/" data-layout="button_count"

    data-size="small" data-mobile-iframe="true"> <a target="_blank" href="https: // www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fdevelopers.facebook.com%2Fdocs%2Fplugins%2F&amp;src=sdkpreparse" class="fb-xfbml-parse-ignore">Share </a> </div> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  12. !" Hey Dom! You are doing it wrong! Dominik Kundel

    | @dkundel | #ReactAlicante #webComponents #useThePlatform
  13. Use React! import React, { Component } from 'react'; import

    FacebookProvider, { ShareButton } from 'react-facebook'; export default class Example extends Component { render() { return ( <FacebookProvider appId="123456789"> <ShareButton href="http: // www.facebook.com" /> </FacebookProvider> ); } } Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  14. ! What if we could extend HTMLElement Dominik Kundel |

    @dkundel | #ReactAlicante #webComponents #useThePlatform
  15. ! ! ! Web Components Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  16. Spec No. ! ! Custom Elements Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  17. ! Custom Elements Definition class DatePicker extends HTMLElement { constructor()

    { super(); // ... } } customElements.define('date-picker', DatePicker); Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  18. ! Custom Elements Definition class DatePicker extends HTMLInputElement { constructor()

    { super(); // ... } } customElements.define('date-picker', DatePicker, { extends: 'input' }); Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  19. ! Custom Elements Usage <!-- normal custom element --> <date-picker>

    </date-picker> <!-- extended custom element --> <input is="date-picker" /> // via JavaScript document.createElement('date-picker'); document.createElement('input', { is: 'date-picker' }); Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  20. ! Custom Elements Attributes <date-picker value="5" disabled> </date-picker> • Allows

    you to pass information to the component • Only supports "simple" data Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  21. ! Custom Elements Properties const el = document.querySelector('date-picker'); el.value =

    99; el.disabled = false; el.range = ['2018-01-01', '2019-01-01']; • Access via JavaScript • Typically reflected back into attributes but doesn't have to • Supports complex data (arrays, objects, etc.) Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  22. ! Custom Elements Properties class DatePicker extends HTMLElement { //

    ... get disabled() { return this.hasAttribute('disabled'); } set disabled(val) { // Reflect the value of `disabled` as an attribute. if (val) { this.setAttribute('disabled', ''); } else { this.removeAttribute('disabled'); } } // ... } Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  23. Spec No. ! ! HTML Templates Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  24. ! HTML Templates <template id="date-picker-template"> <style> /* ... */ </style>

    <div> <!-- some markup --> </div> <slot> </slot> <div> <!-- more markup --> </div> </template> const tmpl = document.querySelector('#date-picker-template'); tmpl.content.cloneNode( /*deep: */ true); Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  25. Spec No. ! ! Shadow DOM Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  26. ! Shadow DOM class DatePicker extends HTMLElement { constructor() {

    super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.appendChild(tmpl.content.cloneNode(true)); } } Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  27. ! Shadow DOM <date-picker><p>I appear in the slot </p> </date-picker>

    <date-picker> #shadow-root <style> /* "global" styles are limited to this root */ </style> <div> <!-- some markup --> </div> <slot> <!-- paragraph appears here --> </slot> <div> <!-- more markup --> </div> </date-picker> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  28. Spec No. ! ! HTML Imports Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  29. Spec No. ! !" HTML Imports Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  30. ✅ Support is there* * with Polyfills Dominik Kundel |

    @dkundel | #ReactAlicante #webComponents #useThePlatform
  31. ! " Why do I care? Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  32. ! You develop a UI component Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  33. ! Same tools for everyone Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  34. ! Example 1 WebVR with a-frame ! glitch.com/~aframe-basic-guide Dominik Kundel

    | @dkundel | #ReactAlicante #webComponents #useThePlatform
  35. ! Example 2 Progressive Enhancement ! web-share-wrapper by Phil Nash

    Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  36. ! Example 2: web-share-wrapper <web-share-wrapper text="Share this" sharetitle="This amazing thing

    was shared" sharetext="You should really click on the link to learn more" shareurl="http: //example.com/amazing" > <a href="https: //twitter.com/intent/tweet?text=Share+Text&amp;url=SHARE_URL"> Share on Twitter </a> </web-share-wrapper> Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  37. ! Why not earlier? " Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  38. ! Extensible Web Manifesto • The standards process should focus

    on adding new low-level capabilities to the web platform that are secure and efficient. • The web platform should expose low-level capabilities that explain existing features, such as HTML and CSS, allowing authors to understand and replicate them. Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  39. ! " How The Web Sausage Gets Made by Monica

    Dinculescu (@notwaldorf) youtube.com/watch?v=326SIMmRjc8 Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  40. ! Tooling Now (a few...) Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  41. Pick Your Favorite... ! and Let Others Pick Theirs! !

    Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  42. ! Let's build: the last datepicker Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  43. ! Let's build: the last datepicker a rating component Dominik

    Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  44. ⚒ Our tool of choice: LitElement Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  45. ⚒ About LitElement • Written by the Polymer Team •

    "A simple base class for creating custom elements rendered with lit- html" • Uses web standards (no compilation)* • lit-html is powered by HTML templates • ! https://github.com/Polymer/lit-element * Except module bundling Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  46. ! What about Stencil • Stencil was written by the

    Ionic Team • "compiler that generates web components" • Built to bring Ionic to more frameworks than Angular • Inspired by Angular, React and others • Uses TypeScript, decorators, and JSX • ! stenciljs.com Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  47. My first Stencil Component import { Component, Prop } from

    '@stencil/core'; @Component({ tag: 'my-first-component', styleUrl: 'my-first-component.scss', }) export class MyComponent { // Indicate that name should be a public property on the component @Prop() name: string; render() { return <p>My name is {this.name} </p>; } } Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  48. ! I love React though! Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  49. ! I love React though! class XSearch extends HTMLElement {

    connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); const name = this.getAttribute('name'); const url = 'https: // www.google.com/search?q=' + encodeURIComponent(name); ReactDOM.render(<a href={url}>{name} </a>, mountPoint); } } customElements.define('x-search', XSearch); Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  50. ! Let's use a web component! Dominik Kundel | @dkundel

    | #ReactAlicante #webComponents #useThePlatform
  51. ! Let's wrap it up! Dominik Kundel | @dkundel |

    #ReactAlicante #webComponents #useThePlatform
  52. Think about Web Components for any shared UI Dominik Kundel

    | @dkundel | #ReactAlicante #webComponents #useThePlatform
  53. Web Components won't limit your framework choices Dominik Kundel |

    @dkundel | #ReactAlicante #webComponents #useThePlatform
  54. Pick Your Favorite... ! and Let Others Pick Theirs! !

    Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  55. ! One datepicker to rule !em a" ! Dominik Kundel

    | @dkundel | #ReactAlicante #webComponents #useThePlatform
  56. Resources • ! d-k.im/webcomp-stencil • " d-k.im/webcomp-reactalicante • #$ github.com/dkundel/emoji-rating

    • webcomponents.org • ✅ custom-elements-everywhere.com • & github.com/shprink/web-components-todo Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  57. ! Let me know what you think! ! vote-react.dkundel.com Dominik

    Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform
  58. Thank You! ! Dominik Kundel " vote-react.dkundel.com # d-k.im/webcomp-reactalicante $

    @dkundel % [email protected] & github/dkundel Dominik Kundel | @dkundel | #ReactAlicante #webComponents #useThePlatform