Build Reusable UI with Web Components: A Step‑by‑Step Counter Example
Learn how to create reusable, encapsulated UI components using Web Components by building a simple counter element with Custom Elements, Templates, Shadow DOM, properties, events, and attributes, and see how to integrate it into any framework, handle data binding, and dispatch custom events.
Custom Elements
Custom Elements API allows defining new HTML tags by extending
HTMLElement. A minimal custom element can be created with a class that defines a constructor and
connectedCallback, then registered with
customElements.define.
<code>class XCounter extends HTMLElement {
constructor() {
super();
this._value = 0;
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>button, p {display:inline-block;}</style>
<button aria-label="decrement">-</button>
<p>0</p>
<button aria-label="increment">+</button>`;
this._setup();
}
_setup() {
this._valueElement = this.shadowRoot.querySelector('p');
this._incBtn = this.shadowRoot.querySelectorAll('button')[1];
this._decBtn = this.shadowRoot.querySelectorAll('button')[0];
this._incBtn.addEventListener('click', () => this.value++);
this._decBtn.addEventListener('click', () => this.value--);
}
set value(v) {
this._value = v;
this._valueElement.innerText = v;
this.dispatchEvent(new CustomEvent('valueChange', {detail: v}));
}
get value() { return this._value; }
static get observedAttributes() { return ['value']; }
attributeChangedCallback(name, oldVal, newVal) {
if (name === 'value') this.value = parseInt(newVal, 10);
}
}
customElements.define('x-counter', XCounter);
</code>Properties
The component exposes a public
valueproperty with getter and setter. Changing the property updates the displayed number and fires a
valueChangecustom event.
Events
Consumers can listen for the
valueChangeevent to react when the counter changes.
<code>const counter = document.querySelector('x-counter');
counter.addEventListener('valueChange', e => console.log('new value:', e.detail));
counter.value = 10;
</code>Attributes
Initial values can be passed via the
valueattribute. The attribute is observed and synchronized with the property.
<code><x-counter value="5"></x-counter>
</code>Summary
Web Components provide a standards‑based way to build reusable UI widgets that work across frameworks. By combining Custom Elements, Templates, and Shadow DOM you get encapsulation, style isolation, and a clean API for properties, events, and attributes.
QQ Music Frontend Team
QQ Music Web Frontend Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.