Web Components: Native, Reusable UI Without a Framework


author: Madan

date:

read time: ~1 min

tags: [webcomponents] [js]


Web Components are the browser’s native way to create reusable UI elements with their own styles and logic, no framework required.

Web Components let you create custom HTML elements with encapsulated styles and behavior, using browser APIs. No framework required. They work in React, Angular, plain HTML, whatever. That portability is the whole point.

1. Define a Custom Element

class MyBadge extends HTMLElement {
  connectedCallback() {
    const label = this.getAttribute("label") ?? "Default";
    this.innerHTML = `<span class="badge">${label}</span>`;
  }
}

customElements.define("my-badge", MyBadge);

Use it anywhere:

<my-badge label="New"></my-badge>

2. Add Style Isolation with Shadow DOM

class MyCard extends HTMLElement {
  connectedCallback() {
    const root = this.attachShadow({ mode: "open" });
    root.innerHTML = `
      <style>
        .card {
          padding: 12px;
          border-radius: 12px;
          border: 1px solid #ddd;
          font-family: sans-serif;
        }
      </style>
      <div class="card">
        <slot></slot>
      </div>
    `;
  }
}

customElements.define("my-card", MyCard);

Usage:

<my-card>
  Hello inside a styled box
</my-card>

The .card styles don’t leak out. Outside CSS doesn’t break it. Finally, peace.

3. Reactivity via Attributes

class MyCounter extends HTMLElement {
  static get observedAttributes() {
    return ["count"];
  }

  attributeChangedCallback() {
    this.render();
  }

  connectedCallback() {
    if (!this.hasAttribute("count")) this.setAttribute("count", "0");
    this.render();
    this.addEventListener("click", () => {
      this.count++;
    });
  }

  get count() {
    return Number(this.getAttribute("count"));
  }
  set count(v) {
    this.setAttribute("count", String(v));
  }

  render() {
    this.textContent = `Count: ${this.count}`;
  }
}

customElements.define("my-counter", MyCounter);

No framework state. Just attributes and lifecycle.

Why Use Web Components

  • Framework-agnostic: write once, use in any stack.
  • Encapsulation: Shadow DOM prevents CSS collisions.
  • Longevity: browser standard, not tied to ecosystem churn.
  • Great for: design systems, widgets, microfrontends, shared UI across teams.

They’re not a full app framework. They’re a native component primitive. Use them where portability and isolation matter more than DX sugar.

--- end of article ---