JSFiddle - React, Tailwind, and code Playground
HTML
<template id="counter-template">
<style>
/* styles will be scoped to the component's shadow root */
:host {
--size: 0.5rem;
--color-bg: beige;
}
button {
margin: var(--size);
background-color: var(--color-bg);
}
</style>
<span name="count">0</span>
<button name="decrement">decrement</button>
<button name="increment">increment</button>
<button name="incrementLater">increment later</button>
</template>
<script>
class CounterComponent extends HTMLElement {
static get observedAttributes() {
return ['count']
}
get count() {
return Number(this.getAttribute('count')) || 0;
}
set count(num) {
this.setAttribute('count', num);
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.template = document.getElementById('counter-template');
this._insertTemplate();
this.$dec = this.shadowRoot.querySelector('[name="decrement"]');
this.$inc = this.shadowRoot.querySelector('[name="increment"]');
this.$incLater = this.shadowRoot.querySelector('[name="incrementLater"]');
this.$count = this.shadowRoot.querySelector('[name="count"]');
this.$dec.addEventListener('click', this.decrement.bind(this));
this.$inc.addEventListener('click', this.increment.bind(this));
this.$incLater.addEventListener('click', this.incrementLater.bind(this));
}
attributeChangedCallback() {
this._updateCount();
}
connectedCallback() {
this._updateCount();
}
decrement() {
this.count -= 1;
}
increment() {
this.count += 1;
}
incrementLater() {
setTimeout(() => {
this.increment();
}, 1000);
}
_insertTemplate() {
this.shadowRoot.innerHTML = '';
this.shadowRoot.appendChild(this.template.content.cloneNode(true));
}
_updateCount() {
this.$count.textContent = this.count;
}
}
customElements.define('counter-component',...
CSS
counter-component {
display: block;
}
counter-component[count="2"] {
--color-bg: green;
}
counter-component[count^="1"] {
--color-bg: blue;
}