JSFiddle - React, Tailwind, and code Playground

by Numbnut

HTML

<body>
<script type="module">
    import htmel from "https://unpkg.com/htmel@latest/dist/htmel.min.js"

    // 30 lines to achieve React-like behaviour, while using web standards:
    // CustomElements, ShadowRoot, MutationObserver, Attributes.
    class HtmElement extends HTMLElement {
        constructor(state) {
            super();
            // Props and state, like in React
            this.state = state || {};
            this.props = {};

            const updateProp = attr => {
                this.props[attr] = (this[attr] === undefined ? this.getAttribute(attr) : this[attr])
            }

            // Put current attributes into props
            [...this.attributes].forEach(attr => updateProp(attr.name))

            // Observe the custom element for attribute changes using MutationObserver, and update the props
            const addProp = mutationsList => mutationsList.forEach(mutation => updateProp(mutation.attributeName));
            new MutationObserver(addProp).observe(this, {attributes: true});

            // Add shadow DOM
            this.attachShadow({mode: 'open'});

            // Create template and append to custom element
            this.shadowRoot.appendChild(this.render());
        }

        get html() {
            return htmel(this.props, this.state)
        }
    }

    // Define custom element
    customElements.define("my-list-item", class extends HtmElement {
        render() {
            return this.html`
            <button onclick=${() => this.props.clicked()}>
                click me for the ${() => this.props.clicks}th time.
            </button>
            `
        }
    })

    // Define another custom element
    customElements.define("my-custom-element", class extends HtmElement {
        constructor() {
            // Send state to parent
            super({
                items: [
                    {clicks: 0},
                    {clicks: 0}
                ],
                margin: 20
            })
 ...