Cross Framework Components

❤️

What / why

Building

Using

Profit

🏗

👩‍💻

🎉

Setting the scene

Component based development

Reusability

My team uses React

My team uses Vue

😢

Web Components

What are Web Components?

  • Based on existing web standards
  • A set of 'new' standards
  • Recommended W3C Standards

Standards

  • Custom Elements
  • Shadow DOM
  • ES Modules
  • HTML Template

Custom Elements

Shadow DOM

ES Modules

 

HTML Templates

So...

Building a
Web Component

Build the component

function getStyles() { /*...*/ }

function getTemplate(styles) { /*...*/ }

class SocialShareNative extends HTMLElement {
    constructor() {
        this._shadowRoot = this.attachShadow({ mode: 'open' })
        this._shadowRoot.innerHTML = getTemplate(getStyles())
    }

    connectedCallback() { /*...*/ }
    
    get show() {
        return this.hasAttribute('show')
    }
    
    set show(val) {
        val
            ? this.setAttribute('show', '')
            : this.removeAttribute('show')
    }

}

customElements.define('social-share-native', SocialShareNative);
function getTemplate(styles) {
    return`
        ${styles}
        <div class="wrapper">
            <strong class="platform">JS</strong>
            <button class="toggle"><img src="/images/share.svg" alt="share"/></button>
            <ul class="list">
                <li class="list-item">
                    <button data-platform="facebook">
                        <img src="/images/facebook.svg" alt="facebook"/>
                    </button>
                </li>
                <li class="list-item">
                    <button data-platform="twitter">
                        <img src="/images/twitter.svg" alt="twitter"/>
                    </button>
                </li>
                <li class="list-item">
                    <button data-platform="whatsapp">
                        <img src="/images/whatsapp.svg" alt="whatsapp"/>
                    </button>
                </li>
            </ul>
        </div>
    `
}
connectedCallback() {
    const wrapper = this._shadowRoot.querySelector('.wrapper') 
    const toggle = this._shadowRoot.querySelector('.toggle')
    const listItemButtons = Array.from(this._shadowRoot.querySelectorAll('.list-item button'))

    wrapper.addEventListener('click', event => {
        if (event.target === toggle) {
            this.show = !this.show
        }

        if (listItemButtons.indexOf(event.target) !== -1) {
            this.dispatchEvent(
                new CustomEvent('share-to', { 
                    detail: event.target.dataset.platform,
                    bubbles: true,
                })
            )
            this.show = false
        }
    })
}
function getStyles() {
    return `
        <style>
            /* A lot more css code */

            :host([show]) .toggle {
                background-color: blue;
            }

            
            :host(:not([show])) .list-item {
                transform: translate(0) !important;
                opacity: 0;
            }

        </style>
    `
}

Use the
Web Component

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    
        <title>Social Share Native</title>
    </head>
    <body>
    
        <social-share-native></social-share-native>

        <script type="module" src="native/social-share-native.js"></script>
    </body>
</html>

Plain HTML

import 'path/to/social-share-native.js'

class App extends React.Component {
            
    constructor(props) {
        super(props);
        this.state = {
            open: undefined
        }
    }

    render() {
        return <social-share-native show={this.state.open}/>;
    }
}

React

<template>
    <social-share-native :show="open"></social-share-native>
</template>

<script>
    import 'path/to/social-share-native'

    export default {
        data: () => ({
            open: false
        })
    }
</script>

Vue

 

🎉

 

 

"But... But... But...
I know React!

Their tooling is way superior!!1!11!"

Stencil JS

  • Uses JSX
  • Uses classes
  • Full TypeScript support
  • React devs will feel right at home
import { Component, Prop, State, Event, EventEmitter } from '@stencil/core';

@Component({
  tag: 'social-share-stencil',
  styleUrl: 'social-share-stencil.css',
  shadow: true
})
export class SocialShareStencil {

  @Prop({ mutable: true, reflectToAttr: true}) show: boolean;
  @Event({ eventName: 'share-to', bubbles: true }) shareTo: EventEmitter
  @State() platforms = ['facebook', 'twitter', 'linkedin', 'whatsapp']

  render() {
    return (
      <div class="wrapper">
        {/* All template code */}
      </div>
    );
  }
}

Svelte JS

  • Syntax very close to Vue
  • Focus on HTML, CSS and JS

"Svelte turns your templates into tiny,

framework-less vanilla JavaScript"

<div class="wrapper">
	<!-- Rest of template code -->
</div>

<style>
	.wrapper {
		position: relative;
	}
	/* Rest of css code */
</style>

<script>
	export default {
		tag: 'social-share-svelte',
		props: ['show'],
		data: () => ({ show: false }),
		oncreate() { /* .. */ },
		methods: {
			choosePlatform(platform) { /* Dispatch event */ }
		}
	};
</script>

VueJS

  • Use a familiar framework
  • All baked into Vue-cli 3

 

⚠️ I'd advise agains it... ⚠️

React JS

Creating web components in frameworks you are familiar with

The X in
Cross Framework Components

Use natively

Use in React

Use in Vue

Usecases

From now on
Web Components all the way?

Stateless components

Web Components

⬇️

Thank you!

cross-framework-components

By Peter Goes

cross-framework-components

  • 1,352