@JagReehal

Build components NOT walls

Jagvinder Singh Reehal

I'm Jagvinder Singh Reehal

  • Contractor living in Cambridge
  • Clients include Arm, Compare The Market, Cambridge Assessment, Ford, Reed Elsevier and Cambridge University Press
  • Web developer since I graduated in 2000
  • Used loads of libraries and frameworks
  • Currently tech lead on a project using Vue and GraphQL

Two of the biggest changes in web development

  • State
  • Components
    For me React was the first library that made this possible

A component should be...

  • small
  • reusable
  • testable
  • documented
  • of high quality (accessibility etc.)
  • good at JUST one thing
  • styleable

A component should also...

  • have few or no dependencies?
  • look and behave the same across browsers?
  • work regardless of what else is on the page?
  • be lazy loadable?
  • be as easy to use as an HTML element?
  • be able to be used by non-techies 🤓 without JS knowledge?

Let's build a component

  • We're a React shop
  • Our component uses hooks... but not all of our apps support hooks
  • Do other applications within the organisation use the same library/framework?
  • What if your organisation acquires another organisation?
  • If your organisation publishes components do you maintain and try to keep feature parity with all versions?

What about a web component?

What is the Shadow Dom?

Styling Components

  • Styling components can be done using
    • Regular CSS
    • CSS modules
    • CSS-in-JS
    • Shadow DOM
  • Let's see how they cope with class style 💣
    and element style 👻

React Component using CSS

React component using CSS-in-JS

                    
const View = styled.div`
  color: #4d4d4d;
`;

// used like this

<View>
...
</View>
                    
                  
                    
.htZyQy {
  color: #4d4d4d;
}                      

...

Shadow Dom (NOT EFFECTED)

Themed Shadow Dom

            
:host{
  background-color: #FFF:
}                
:host(.dark) {
  background-color: #000:
}             
            
          

CSS Variables Shadow Dom

            
:root {
  --todo-item-background-color: orange;
  --todo-item-color: blue;
  --todo-destroy-color: black;
}         
            
          

Use your own (styled) content using a slot

            

<todo-item>
  <slot/>  
</todo-item>
            
          

Shadow DOM pitfalls

  • Don't work well in forms... yet
  • Polyfills (more on this later)
  • 'all: initial' vs inherited properties
  • Closed mode is evil

Thanks for coming!

#UseThePlatform

if only it was that simple...

Web component troubles

  • Spec change (v0 to v1) is still confusing
  • Polymer the 'flagship' for web components was awful
  • Horrible developer experience (example)
  • All this at the time when other libraries and frameworks made things look simple
  • Outdated - The broken promise of Web Components
  • Attributes vs props confusion - Why I don't use web components by Rich Harris
  • The biggest problem is...

The web platform is and always will be consistently inconsistent

However... usage is growing

6% of all pages today use web components

Source: Chrome Status

Support is excellent

browser support

Seamless integration with MOST libraries and frameworks...

React 😞

Vanilla web components are & will always be 💩

"Just in the same way we don't ship vanilla JavaScript, no one will ship vanilla web components either"
Jag Reehal

Lots of options!

I ♥️ Stencil

  • Use by adding script tag
  • Dynamic polyfills
  • Modern and legacy builds
  • Supports IE11
  • Tree shaking (via Rollup)
  • Unit, visual and end-to-end tests
  • Built in documentation generation
  • Reactive
  • Virtual DOM
  • Server side rendering
  • Pre-rendering
  • Typescript (TSX)
  • Great community
  • Used by Ionic instead of Angular

The Era of Disappearing Frameworks

  • Like Svelte, Stencil uses compilation
  • Which results in a minimal runtime and computed bundling

Integrating web components

I refactored React & Vue versions of TODO MVC to use the SAME web components
  • Create web component, write tests and Storybook story
  • Replace native component with web component
  • Run E2E tests using Cypress.io after each step
  • TL;DR - smaller build, state management still the same

Stencil Todo Input

            
import { Component, State, Event, EventEmitter, h } from '@stencil/core';

@Component({
  tag: 'todo-input'
})
export class TodoInput {
  @Event({ eventName: 'input-submit' }) inputSubmit: EventEmitter;
  @State() value: string;

  keyUp = e => {
    if (e.keyCode === 13) {
      this.inputSubmit.emit(this.value);
      this.value = '';
    }
  };

  render() {
    return (
      <input
        class="new-todo"
        value={this.value}
        type="text"
        autoFocus
        placeholder="What needs to be done?"
        onInput={(ev: any) => (this.value = ev.target.value)}
        onKeyUp={e => this.keyUp(e)}
      />
    );
  }
}
            
          

Integrating Stencil

Used like this in React

  • Before
                const TodoInput = () => {
      const [textInput, onInputChange] = useState('');
      const { onSubmitTodo } = React.useContext(TodoStoreContext);
      const handleInputEnterPress = e => {
        if (e.key === 'Enter') {
          onSubmitTodo(textInput);
          onInputChange('');
        }
      };
      return (
        <>
          <input
            onKeyPress={handleInputEnterPress}
            className="new-todo"
            placeholder="What needs to be done?"
            autoFocus
            value={textInput}
            onChange={e => onInputChange(e.target.value)}
          />
        </>
      );
    };
              
  • After
                    const TodoInput = () => {
      const { onSubmitTodo } = React.useContext(TodoStoreContext);
    
      const [customElementProps, ref] = useCustomElement({
        'input-submit': onSubmitTodo
      });
      return <todo-input autofocus {...customElementProps} ref={ref} />;
    };

Used like this in Vue

  • Before
                   
    <input class="new-todo"
           autofocus
           autocomplete="off"
           placeholder="What needs to be done?"
           v-model="newTodo"
           @keyup.enter="addTodo" />         
                
              
  • After
                    
    // tell Vue not to panic we know what we're doing                
    Vue.config.ignoredElements = ['todo-input'];                
    
    <todo-input @input-submit="addTodo"/>
    

But is it fast?

According to Lighthouse...
  • React

    Before

    100

    After

    100
  • Vue

    Before

    100

    After

    100

DX using Stencil web components

  • Intellisense
  • Typescript
  • Storybook documentation using Stencil
  • Testing has to change from unit to E2E - Write tests. Not too many. Mostly integration by Kent Dodds
  • Use as any other HTML element
  • Culture and resource has to support the change

Production ready?

Companies that use web components

  • Arm
  • Salesforce
  • Amazon
  • Bloomberg
  • Porsche
  • EA Sports
  • Google
  • Samsung
  • Github
  • McDonalds
  • Coca Cola
  • Microsoft
  • Mixpanel
  • City of Boston

Thanks for coming!

  • Use whatever works for you
  • It's about composable, collaborative UI components NOT vs.
  • Grab some popcorn and watch the big frameworks and libraries fight it out
  • Questions?