Going Reactless* with Web Components

> whoami

  • Elton Pinto
  • 🐝 cs major @gatech
  • 💻 software engineering intern, innovation lab @ncr
  • 🧩 speedcube aficionado
  • @1ntEgr8 on github and twitter
A question...
                            
                                
                                    
                                         
                                        
                                        ...
                                    
                                    
                                
                            
                        

Yes!!!

  • With Web Components, you can define your own custom HTML tags
  • The browser will use the definition you provided to render HTML and CSS, and will run any pertaining JS

What are Web Components?

  • A collection of technologies that allow you to create reusable and encapsulated components
  • Supported natively in every browser
    • no framework required*
  • Lightweight

Framework agnostic

Showcase

<model-viewer> by Google
ERD Editor Note: keyboard shortcut to advance to next slide is disabled. Click the arrow buttons on the bottom right to navigate.

Let's build a Web Component!

What are we building?

<an-incdec>

We're going to be using three W3C Specifications:
    Custom Elements This feature lets you tell the browser to identify <your-tag> as a valid HTML tag
    Shadow DOM This allows you to encapsulate your styles so that it doesn't affect other DOM nodes.
    HTML Templates This can help you avoid interpolating HTML in javascript
Set up the class in index.js
                            
                            class IncDec extends HTMLElement {
                                constructor() {
                                    super();

                                    const dummyEl = document.createElement('div');
                                    dummyEl.innerHTML = 'hello';
                                    this.appendChild(dummyEl);
                                }
                                
                                connectedCallback() {

                                }
                            }

                            customElements.define('an-incdec', IncDec);
                            
                        
You can now use <an-incdec> in your HTML and it will render 'hello'
Let's specify an HTML template in index.html
                            
                                
                            
                        
Don't worry about what :host means just yet. It will make more sense when we talk about the Shadow DOM
Use the template in index.js
                            
                            class IncDec extends HTMLElement {
                                constructor() {
                                    super();

                                    const template = document.getElementById("incdec-template");
                                    const el = template.content.cloneNode(true); 
                                    this.appendChild(el);
                                }
                                
                                connectedCallback() {

                                }
                            }

                            customElements.define('an-incdec', IncDec);
                            
                        
The code will render the UI fine, but the styles will leak out because we are not using the Shadow DOM. Let's fix that!
Unleash the Shadow DOM (and add business logic)
                            
                            class IncDec extends HTMLElement {
                                constructor() {
                                    super();
                                    
                                    this.attachShadow({mode: 'open'});

                                    const template = document.getElementById("#incdec-template");
                                    const el = template.content.cloneNode(true);
                                    this.shadowRoot.append(el);
                                
                                    this._count = 0;
                                }
                                
                                get count() {
                                    return this._count;
                                }
                                
                                set count(val) {
                                    if (val < 0) {
                                        alert("cannot go less than zero");
                                        return;
                                    }
                                
                                    this._count = val;
                                    this.shadowRoot.querySelector("#count").innerHTML = this.count;
                                }
                                
                                connectedCallback() {
                                    this.count = 0;
                                
                                    this.shadowRoot.querySelector("#dec").addEventListener("click", () => {
                                        this.count -= 1;            
                                    });
                                
                                    this.shadowRoot.querySelector("#inc").addEventListener("click", () => {
                                        this.count += 1;            
                                    });
                                }
                            }

                            customElements.define('an-incdec', IncDec);
                            
                        
Whatever styles you set in the <style> is scoped to just your component. It WILL NOT leak out
Feel free to fiddle with this on CodePen!

See the Pen NWxONbb by Elton Leander Pinto (@1ntegr8) on CodePen.

Don't drink too much Kool-Aid!

  • The vanilla way to write Web Components is verbose
  • What about state, props, composition? The API is imperative in nature!

Solutions

  • hybrids
    • Let's you write Web Components with a mixture of OOP and FP
  • lit-element
    • Google's library for making Web Components
  • stenciljs
    • A toolchain for building design systems that comes with a virtual DOM and feels like React
Implementation of <an-incdec> in hybrids
                            
                                import { html, define } from 'hybrids';

                                export function inc(host) {
                                    host.count += 1;
                                }

                                export function dec(host) {
                                    host.count -= 1;
                                }

                                export const IncDec = {
                                    count: 0, 
                                    render: ({ count }) => html`
                                        
                                        ${count}
                                        
                                    `,
                                }

                                define('an-incdec', IncDec);
                            
                        
Do I ditch existing front-end frameworks?
                        
                            import React from "react";
                            
                            class App extends React.Component {
                                ...

                                render() {
                                    return (
                                        
A cool web component!
); } }
No! Web Components are compatible with every framework. In the above example, we are using our component in React.

Let's talk use cases!

component libraries

  • It's the perfect fit for establishing consistent UIs across all web apps
  • Companies like Apple, Google, Salesforce, SpaceX, ... are making component libraries with Web Components!
  • open-wc and stenciljs are good resources to get you started
  • Feel free to check out this template that makes writing component monorepos simpler

the UNIX philosophy

  • Do one thing, but do it really well!
  • You can write some very performant code (using Web Assembly), pack it into a web component, and ship it!
  • Your teams can use this highly performant component across frameworks and web apps

Summary

  • Web Components natively allow you to encapsulate HTML, CSS and JS to create reusable components for the web
  • Since it is a spec, it is supported wherever HTML is supported
  • It does have some kinks, but frameworks like hybrids make it a lot more ergonomic to write web components
  • You can build component libraries, and highly performant components to share across teams

Thanks!