Learning how to create a basic Web Component

NicolasBrondinBernard

Author
@NicolasBrondinBernard

Learn how to create your first Web Component with HTML, CSS, and JavaScript. This step-by-step guide shows you how to build reusable, encapsulated elements using modern Web technologies.

Article published on 19/05/2025, last updated on 10/08/2026

You may have heard of Web Components, these reusable, native, encapsulated HTML components that can work without a framework.

They are made possible by a key browser technology: the Shadow DOM.

We're going to see how to create your own Web Component in plain JavaScript, with its own embedded style, structure, and logic.

What is a Web Component?

A Web Component is a custom HTML tag that you define yourself. Once created, you can use it like any other HTML tag in your page.

Here's a basic example:

<gift-box></gift-box>

Behind this simple tag lies a self-contained component, which can contain HTML, CSS, JavaScript… all isolated from the rest of the page.

Step 1: Create a JavaScript class

A Web Component must always start with a class that extends HTMLElement:

class Gift extends HTMLElement {
  constructor() {
    super();
  }
}

Then, we register it with customElements.define:

customElements.define("gift-box", Gift);

customElements is an API natively provided by modern browsers!

The <user-badge> tag is now recognized by the browser.

Step 2: Add a Shadow DOM

To encapsulate our component, we use the attachShadow method:

constructor() {
  super();
  this.shadow = this.attachShadow({ mode: "open" });
}

The "open" mode allows you to access the Shadow DOM from the outside via .shadowRoot.

But you can use "closed" to make it completely private.

If you're not familiar with the concept of the Shadow DOM, here's a detailed article that explains everything: https://code-garage.com/blog/comprendre-le-shadow-dom

Step 3: Create an HTML template

We can now build the content of our component:

this.shadow.innerHTML = `
  <style>
    .gift {
      display: inline-block;
      padding: 8px 12px;
      background-color: #eee;
      border-radius: 8px;
      font-weight: bold;
    }
  </style>
  <button class="gift">🎁 (click to open)</button>
`;

The style is local to the Shadow DOM: it doesn't affect other elements, and can't be affected by global styles.

Step 4: Add JavaScript interaction

We can add events just like in a classic component:

const gift = this.shadow.querySelector(".gift");
gift.addEventListener("click", () => {
  gift.textContent = "🌸🌹🌻 (here are some flowers)";
});

Everything remains contained within the component, without any dependency or global pollution.

Complete example

class Gift extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });

    this.shadow.innerHTML = `
      <style>
        .gift {
          padding: 8px 12px;
          background-color: #eee;
          border-radius: 8px;
          font-weight: bold;
          cursor: pointer;
        }
      </style>
      <button class="gift">🎁 (click to open)</button>
    `;

    const gift = this.shadow.querySelector(".gift");
    gift.addEventListener("click", () => {
      gift.textContent = "🌸🌹🌻 (here are some flowers)";
    });
  }
}

customElements.define("gift-box", Gift);

And in your HTML:

<gift-box></gift-box>

Why use Web Components?

Web Components allow you to:

  • Create reusable interfaces without depending on a framework
  • Encapsulate HTML, CSS, and logic
  • Reduce the risk of style conflicts
  • Easily integrate components into any project

They are supported by all modern browsers, and can coexist with React, Vue, or Angular without any problem.


Finished reading this article?
Our newsletter

No spam. Only free content, news, and ever more resources to level up your skills!

Join +1500 developers

Comments (0)

to leave a comment

No comments yet