WebComponents in 2023: A Comprehensive Exploration

A presentation at Riviera Dev in July 2023 in Sophia Antipolis, France by Horacio Gonzalez

Slide 1

Slide 1

WebComponents in 2023: A Complete Exploration Horacio Gonzalez 2023-07-10

Slide 2

Slide 2

Who are we? Introducing myself and introducing OVHcloud

Slide 3

Slide 3

Horacio Gonzalez @LostInBrittany Spaniard Lost in Brittany

Slide 4

Slide 4

OVHcloud Web Cloud & Telcom 30 Data Centers in 12 locations 1 Million+ Servers produced since 1999 Private Cloud 34 Points of Presence on a 20 TBPS Bandwidth Network 1.5 Million Customers across 132 countries Public Cloud 2200 Employees worldwide 3.8 Million Websites hosting Storage 115K Private Cloud VMS running 1.5 Billion Euros Invested since 2016 300K Public Cloud instances running P.U.E. 1.09 Energy efficiency indicator 380K Physical Servers running in our data centers 20+ Years in Business Disrupting since 1999 Network & Security

Slide 5

Slide 5

We want the code! https://github.com/LostInBrittany/web-components-in-2023/

Slide 6

Slide 6

What the heck are web component? The 3 minutes context

Slide 7

Slide 7

Web Components Web standard W3C

Slide 8

Slide 8

Web Components Available in all modern browsers: Firefox, Safari, Chrome

Slide 9

Slide 9

Web Components Create your own HTML tags Encapsulating look and behavior

Slide 10

Slide 10

Web Components Fully interoperable With other web components, with any framework

Slide 11

Slide 11

Web Components CUSTOM ELEMENTS SHADOW DOM TEMPLATES

Slide 12

Slide 12

Custom Element To define your own HTML tag <body> … <script> window.customElements.define(‘my-element’, class extends HTMLElement {…}); </script> <my-element></my-element> </body>

Slide 13

Slide 13

Shadow DOM To encapsulate subtree and style in an element <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); const shadowRoot = host.attachShadow({mode:’open’}); shadowRoot.textContent = ‘こんにちは、影の世界!’; </script>

Slide 14

Slide 14

Template To have clonable document template <template id=”mytemplate”> <img src=”” alt=”great image”> <div class=”comment”></div> </template> var t = document.querySelector(‘#mytemplate’); // Populate the src at runtime. t.content.querySelector(‘img’).src = ‘logo.png’; var clone = document.importNode(t.content, true); document.body.appendChild(clone);

Slide 15

Slide 15

But in fact, itʼs just an element… ● ● ● ● Attributes Properties Methods Events

Slide 16

Slide 16

Sometimes I feel a bit grumpy The stories of the grumpy old speaker…

Slide 17

Slide 17

On Polymer tour since 2014

Slide 18

Slide 18

Image: bu.edu Web components == Revolution

Slide 19

Slide 19

Images: BitRebels & Brickset Building a world brick by brick

Slide 20

Slide 20

Is the promise unfulfilled? It’s 2023 now, where is your revolution, dude?

Slide 21

Slide 21

Is it a conspiracy?

Slide 22

Slide 22

Am I only a dreamer?

Slide 23

Slide 23

Well, revolution IS there But it’s a silent one…

Slide 24

Slide 24

I as looking for a great example

Slide 25

Slide 25

New Reddit runs on Web Components

Slide 26

Slide 26

Often hidden in plain sight

Slide 27

Slide 27

Vanilla Web Components

Slide 28

Slide 28

Let’s build a vanilla Web Component Using only HTML, CSS & JS, no library needed

Slide 29

Slide 29

A very basic web component class HelloWorld extends HTMLElement { // This gets called when the HTML parser sees your tag constructor() { super(); // always call super() first in the ctor. this.msg = ‘Hello World!’; } // Called when your element is inserted in the DOM or // immediately after the constructor if it’s already in the DOM connectedCallback() { this.innerHTML = <p>${this.msg}</p>; } } customElements.define(‘hello-world’, HelloWorld);

Slide 30

Slide 30

Custom Elements: ● Let you define your own HTML tag with bundled JS behavior ● Trigger lifecycle callbacks ● Automatically “upgrade” your tag when inserted in the document

Slide 31

Slide 31

Custom Elements donʼt: ● Scope CSS styles ○ Shadow DOM ● Scope JavaScript ○ ES2015 ● “Reproject” children into <slot> elements ○ Shadow DOM

Slide 32

Slide 32

Adding ShadowDOM class HelloWithShadowdom extends HTMLElement { // This gets called when the HTML parser sees your tag constructor() { super(); // always call super() first in the ctor. this.msg = ‘Hello World from inside the ShadowDOM!’; this.attachShadow({ mode: ‘open’ }); } // Called when your element is inserted in the DOM or // immediately after the constructor if it’s already in the DOM connectedCallback() { this.shadowRoot.innerHTML = <p>${this.msg}</p>; } } customElements.define(‘hello-with-shadowdom’, HelloWithShadowdom);

Slide 33

Slide 33

Using web components <!DOCTYPE html> <html> <head> <title>Vanilla Web Components</title> <script src=”./hello-world.js”></script> <script src=”./hello-with-shadowdom.js”></script> </head> <body> <hello-world></hello-world> <hello-with-shadowdom></hello-with-shadowdom> </body> </html>

Slide 34

Slide 34

Using web components

Slide 35

Slide 35

Lifecycle callbacks class MyElementLifecycle extends HTMLElement { constructor() { // Called when an instance of the element is created or upgraded super(); // always call super() first in the ctor. } static get observedAttributes() { // Tells the element which attributes to observer for changes return []; } connectedCallback() { // Called every time the element is inserted into the DOM } disconnectedCallback() { // Called every time the element is removed from the DOM. } attributeChangedCallback(attrName, oldVal, newVal) { // Called when an attribute was added, removed, or updated } adoptedCallback() { // Called if the element has been moved into a new document } }

Slide 36

Slide 36

my-vanilla-counter element class MyVanillaCounter extends HTMLElement { constructor() { super(); this._counter = 0; this.attachShadow({ mode: ‘open’ }); } connectedCallback() { this.render(); this.display(); } static get observedAttributes() { return [ ‘counter’ ] } // We reflect attribute changes into property changes attributeChangedCallback(attr, oldVal, newVal) { if (oldVal !== newVal) { this[attr] = newVal; } }

Slide 37

Slide 37

my-counter custom element // Getter and setters for counter get counter() { return this._counter; } set counter(value) { if (value != this._counter) { this._counter = Number.parseInt(value); this.setAttribute(‘counter’, value); this.display(); } } increment() { this.counter = this.counter + 1; this.dispatchEvent(new CustomEvent(‘increased’, {detail: {counter: this.counter}})); }

Slide 38

Slide 38

my-counter custom element render() { let container = document.createElement(‘div’); container.style.display = ‘flex’; … this.style.fontSize = ‘5rem’; } display() { this.output.innerHTML = ${this.counter}; } } customElements.define(my-vanilla-counter, MyVanillaCounter);

Slide 39

Slide 39

my-counter-with-templates let template = ` <style> … </style> <div class=”container”> <div id=”icon”> <img src=”${import.meta.url}/../img/logo.png”>

</div> <div id=”value”> 0 </div> </div> `;

Slide 40

Slide 40

my-counter-with-templates render() { let templ = document.createElement(‘template’); templ.innerHTML = template; this.shadowRoot.appendChild(templ.content.cloneNode(true)); let button = this.shadowRoot.getElementById(‘icon’); button.addEventListener(‘click’, this.increment.bind(this)); } display() { console.log(this.shadowRoot.getElementById(‘value’)) this.shadowRoot.getElementById(‘value’).innerHTML = ${this.counter}; }

Slide 41

Slide 41

Coding my-counter

Slide 42

Slide 42

my-counter custom element

Slide 43

Slide 43

Why those libs? Why people don’t use vanilla?

Slide 44

Slide 44

Web component standard is low level At it should be!

Slide 45

Slide 45

Standard == basic bricks Standard exposes an API to: ○ Define elements ○ Encapsulate DOM

Slide 46

Slide 46

Libraries are helpers They give you higher-level primitives

Slide 47

Slide 47

Different high-level primitives Each one tailored to a use

Slide 48

Slide 48

Sharing the same base High-performant, low-level, in-the-platform web components standard

Slide 49

Slide 49

Libraries aren’t a failure of standard They happen by design

Slide 50

Slide 50

A library for building reusable, scalable component libraries

Slide 51

Slide 51

Not another library A Web Component toolchain

Slide 52

Slide 52

A build time tool To generate standard web components

Slide 53

Slide 53

Fully featured ● Web Component-based ● Component pre-rendering ● Asynchronous rendering pipeline ● Simple component lazy-loading ● TypeScript support ● JSX support ● Reactive Data Binding ● Dependency-free components

Slide 54

Slide 54

And the cherry on the cake Server-Side Rendering

Slide 55

Slide 55

Stencil leverages the web platform

Slide 56

Slide 56

The Stencil story A company tired of putting good code in the bin

Slide 57

Slide 57

Once upon a time there was a fight Between native apps and web app on mobile

Slide 58

Slide 58

A quest to the perfect solution Hybrid apps, leveraging on web technologies

Slide 59

Slide 59

A company wanted to do it well The perfect technology for mobile web and hybrid apps

Slide 60

Slide 60

The time is 2013 So what technology would you use?

Slide 61

Slide 61

Really soon after launch… Hey folks, we are killing AngularJS!

Slide 62

Slide 62

What did Ionic people do? Let’s put everything in the trash bin and begin anew

Slide 63

Slide 63

But times have changed… In 2013 Angular JS was the prom queen

Slide 64

Slide 64

Times have changed… In 2017 Angular is only one more in the clique

Slide 65

Slide 65

Angular limits adoption of Ionic Devs and companies are very vocal about JS Frameworks

Slide 66

Slide 66

What did Ionic people do? Let’s put everything in the trash bin and begin anew… But on which framework?

Slide 67

Slide 67

What about web components? A nice solution for Ionic problems: Any framework, even no framework at all!

Slide 68

Slide 68

But what Web Component library? SkateJS There were so many of them!

Slide 69

Slide 69

Let’s do something different A fully featured web component toolchain With all the bells and whistles!

Slide 70

Slide 70

Ionic rewrote all their code again From Ionic 4 is fully based on Stencil

Slide 71

Slide 71

Now Ionic works on any framework Or without framework at all

Slide 72

Slide 72

And we have Stencil To use it in any of our projects

Slide 73

Slide 73

Hands on Stencil Simply use npm init npm init stencil Choose the type of project to start ? Select a starter project. Starters marked as [community] are developed by the Stencil Community, rather than Ionic. For more information on the Stencil Community, please see https://github.com/stencil-community › - Use arrow-keys. Return to submit. ❯ component Collection of web components that can be used anywhere app [community] Minimal starter for building a Stencil app or website ionic-pwa [community] Ionic PWA starter with tabs layout and routes

Slide 74

Slide 74

Hands on Stencil And the project is initialized in some seconds! ✔ Pick a starter › component ✔ Project name › my-stencil-counter ✔ All setup in 17 ms $ npm start Starts the development server. $ npm run build Builds your components/app in production mode. $ npm test Starts the test runner. We $ $ $ suggest that you begin by typing: cd my-stencil-counter npm install npm start Happy coding! 🎈

Slide 75

Slide 75

Let’s look at the code

Slide 76

Slide 76

Some concepts import { Component, Prop, h } from ‘@stencil/core’; import { format } from ‘../../utils/utils’; @Component({ tag: ‘my-component’, styleUrl: ‘my-component.css’, shadow: true }) export class MyComponent { @Prop() first: string; Decorators

Slide 77

Slide 77

Some concepts @Prop() first: string; @Prop() middle: string; @Prop() last: string; @State() nickname: string; Properties and States

Slide 78

Slide 78

Some concepts render() { return <div>Hello, World! I’m {this.getText()}</div>; } Asynchronous rendering using JSX

Slide 79

Slide 79

Some concepts @Prop() value: number; @Watch(value) valueChanged(newValue: boolean, oldValue: boolean) { console.log(The new value is ${newValue}, it was ${oldValue} before); } Watch

Slide 80

Slide 80

Some concepts @Event() actionCompleted: EventEmitter; someAction(message: String) { this.actionCompleted.emit(message); } @Listen(‘actionCompleted’) actionCompletedHandler(event: CustomEvent) { console.log(‘Received the custom actionCompleted event: ‘, event.detail); } Emitting events

Slide 81

Slide 81

Some concepts @Method() async sayHello() { this.hello = true; } render() { return ( <Host> <h2>{ this.hello ? Hello sthlm.js : ”}</h2> </Host> ); } Asynchronous public methods

Slide 82

Slide 82

Some concepts @Component({ tag: ‘my-component’, styleUrl: ‘my-component.css’, shadow: true }) export class MyComponent { Optional Shadow DOM

Slide 83

Slide 83

Coding my-stencil-counter

Slide 84

Slide 84

Simple. Fast. Web Components

Slide 85

Slide 85

Do you remember Polymer The first Web Component library

Slide 86

Slide 86

It is deprecated… And that means good news!

Slide 87

Slide 87

Let’s try to see clearer Let’s dive into Polymer history…

Slide 88

Slide 88

A tool built for another paradigm No web component support on browsers No React, Angular or Vue innovations

Slide 89

Slide 89

No so well suited for the current one The current platform is way more powerful The state of art has evolved

Slide 90

Slide 90

Let’s learn from its lessons The current platform is way more powerful The state of art has evolved

Slide 91

Slide 91

And let it rest… There will have no Polymer 4…

Slide 92

Slide 92

So Polymer as we know it is dead… But the Polymer Project is indeed alive!

Slide 93

Slide 93

But I have invested so much on it! What to do?

Slide 94

Slide 94

That’s why web components are top You can keep using all your Polymer components and create the new ones with a new library… And it simply works!

Slide 95

Slide 95

Born from the Polymer team For the new web paradigm

Slide 96

Slide 96

Modern lightweight web components For the new web paradigm

Slide 97

Slide 97

Based on lit-html An efficient, expressive, extensible HTML templating library for JavaScript

Slide 98

Slide 98

Do you know tagged templates? function uppercaseExpression(strings, …expressionValues) { var finalString = ” for ( let i = 0; i < strings.length; i++ ) { if (i > 0) { finalString += expressionValues[i - 1].toUpperCase() } finalString += strings[i] } return finalString } const expressions = [ ‘Sophia Antipolis’, ‘RivieraDev’, ‘Thank you’]; console.log(uppercaseJe suis à ${expression[0]} pour ${expression[1]. $expression[2]! Little known functionality of template literals

Slide 99

Slide 99

lit-html Templates let myTemplate = (data) => html<h1>${data.title}</h1> <p>${data.body}</p>; Lazily rendered Generates a TemplateResult

Slide 100

Slide 100

It’s a bit like JSX, isn’t it? The good sides of JSX… but in the standard!

Slide 101

Slide 101

LitElement import { LitElement, html } from ‘lit-element’; // Create your custom component class CustomGreeting extends LitElement { // Declare properties static get properties() { return { name: { type: String } }; } // Initialize properties constructor() { super(); this.name = ‘World’; } // Define a template render() { return html<p>Hello, ${this.name}!</p>; } } // Register the element with the browser customElements.define(‘custom-greeting’, CustomGreeting); Lightweight web-components using lit-html

Slide 102

Slide 102

Coding my-lit-counter

Slide 103

Slide 103

Web Components & Frameworks Less “either/or” and more “both/and”

Slide 104

Slide 104

Compatibility is on Web Components side Web Components everywhere, baby!

Slide 105

Slide 105

They are the interoperable alternative Any framework… or no framework at all

Slide 106

Slide 106

You can have a single implementation And it simply works everywhere*

Slide 107

Slide 107

*React don’t fully support them yet Long story made short: use lit-labs/react

Slide 108

Slide 108

When you need interoperability Nothing beats the standard

Slide 109

Slide 109

Angular can generate web components Angular Elements

Slide 110

Slide 110

Vue can generate web components With defineCustomElement()

Slide 111

Slide 111

React can generate web components But it can generate them too

Slide 112

Slide 112

What about Svelte? Let’s look in detail one case

Slide 113

Slide 113

Web Components & Design Systems One of the best cases for Web Components

Slide 114

Slide 114

So, what are Design Systems? And why should I look at them?

Slide 115

Slide 115

A talk for devs by a dev I am not a designer, neither I play one on TV…

Slide 116

Slide 116

The same or different?

Slide 117

Slide 117

Style Guides A document listing the styles, patterns, practices, and principles of a brand design standards

Slide 118

Slide 118

Style Guides Style guides define the applicationʼs look and feel

Slide 119

Slide 119

Style Guide Example: Uber https://brand.uber.com/

Slide 120

Slide 120

Style Guide Example: Medium https://www.behance.net/gallery/7226653/Medium-Brand-Development

Slide 121

Slide 121

Style Guides alone are ambiguous Interpretation needed to adapt the preconisation to the use case

Slide 122

Slide 122

Component Catalogs A component catalog is a repository of components, with one or several implementations, code examples and technical documentation

Slide 123

Slide 123

Component Catalog example: Bootstrap https://getbootstrap.com/

Slide 124

Slide 124

Component Catalog Example: ING’s Lion https://lion-web-components.netlify.app/

Slide 125

Slide 125

Catalogs alone create inconsistency Like using the same LEGO bricks to create very different objects

Slide 126

Slide 126

Design Systems A Design System is like a common visual language for product teams

Slide 127

Slide 127

Design systems A Design System is a set of design standards, documentations, and principles, alongside with the toolkit (UI patterns and code components) to achieve those standards

Slide 128

Slide 128

Design systems

Slide 129

Slide 129

Example: Carbon Design System https://www.carbondesignsystem.com/

Slide 130

Slide 130

Example: Firefox’s Photon Design System https://design.firefox.com/photon/

Slide 131

Slide 131

Example: Material Design https://material.io/

Slide 132

Slide 132

The component catalog The poor relative of the Design System family

Slide 133

Slide 133

Let’s choose a simple example Bootstrap based component catalogs

Slide 134

Slide 134

A long time ago Components defined in HTML, CSS and some jQuery

Slide 135

Slide 135

Then it was AngularJS time… And new reference implementations were needed

Slide 136

Slide 136

But you know the sad story… All UI Bootstrap based catalogs woke up with an obsolete implementation

Slide 137

Slide 137

Worry no more, let’s do Angular! ng-bootstrap to the rescue

Slide 138

Slide 138

But times had changed… In 2017 Angular is only one more in the clique

Slide 139

Slide 139

TM React is the new Big Thing So let’s build React Bootstrap…

Slide 140

Slide 140

Wait, what about Vue? We also need BootstrapVue

Slide 141

Slide 141

OK, I think you see my point…

Slide 142

Slide 142

Most Design System do a choice Either they choose a canonical implementation or they ship and maintain several implementations

Slide 143

Slide 143

Both choices are problematic Shipping only one implementation: Web dev ecosystem changes quickly and almost nobody keeps the same framework for years…

Slide 144

Slide 144

Both choices are problematic Shipping several implementations: You need to maintain all the implementation… and you still miss some others

Slide 145

Slide 145

Incomplete catalogs are problematic People will need to recode the components in their chosen framework… Coherence is not guaranteed!!!

Slide 146

Slide 146

Example: Carbon Design System

Slide 147

Slide 147

Web Components & Design Systems A match made in heaven

Slide 148

Slide 148

Compatibility is on Web Components side Web Components everywhere, baby!

Slide 149

Slide 149

Do you remember AngularJS? And all the code put in the trash bin when Angular arrived…

Slide 150

Slide 150

The pain of switching frameworks? Rewriting once again your code…

Slide 151

Slide 151

The impossibility of sharing UI code? Between apps written with different frameworks

Slide 152

Slide 152

Web Components change that In a clean and standard way

Slide 153

Slide 153

They are the interoperable alternative Any framework… or no framework at all

Slide 154

Slide 154

They are truly everywhere 🚀 🚀 Even in the spaaaaaaaace 🚀

Slide 155

Slide 155

You can have a single implementation And it simply works everywhere

Slide 156

Slide 156

When you need interoperability Nothing beats the standard

Slide 157

Slide 157

But how to do it? Designing, developing and managing a catalog of Web Components

Slide 158

Slide 158

Learning from the best https://lion-web-components.netlify.app/

Slide 159

Slide 159

Learning from the best https://github.com/CleverCloud/clever-components

Slide 160

Slide 160

What kind of components? From little atomic blocs to big smart components, and everything in between

Slide 161

Slide 161

A matter of size and complexity What kind(s) of components you want to build

Slide 162

Slide 162

Build from the bottom and go up Eat your own dog food

Slide 163

Slide 163

And how to choose the atoms? Flexibility and configurability are key

Slide 164

Slide 164

And how to choose the atoms? Encode often used patterns

Slide 165

Slide 165

And what about the molecules? Capitalize on your atoms Keep the flexibility and configurability

Slide 166

Slide 166

Big smart business components Encoding your business logic

Slide 167

Slide 167

Internal or external customers? Who are your target users?

Slide 168

Slide 168

Internal customers need off-the-shelf components A well defined and coherent look-and-feel

Slide 169

Slide 169

External customers need to be able to tweak Theming and customizing components

Slide 170

Slide 170

How to organize the catalog Packages, imports and pragmatism

Slide 171

Slide 171

A single repository Single source of truth for the catalog

Slide 172

Slide 172

Two schools of thought A packet per component or a global one

Slide 173

Slide 173

Two schools of thought Individual versioning vs global one

Slide 174

Slide 174

Driving-up adoption Making devs use your components

Slide 175

Slide 175

Think who are your target users Users of any framework current or future…

Slide 176

Slide 176

They aren’t used to your library And they shouldn’t need to be

Slide 177

Slide 177

Go the extra mile to drive up adoption So they don’t need to do it

Slide 178

Slide 178

Make it easy to use As easy as a HTML tag

Slide 179

Slide 179

Document every composant How to use, inputs/outputs, examples…

Slide 180

Slide 180

Documentation isn’t enough Storybook make adoption easy

Slide 181

Slide 181

Keeping a coherent writing style Write down your guidelines

Slide 182

Slide 182

I18n shouldn’t be an afterthought Prepare everything for internationalization

Slide 183

Slide 183

That’s all, folks! Thank you all!