Web Components

Discover how to create custom, reusable, and encapsulated HTML elements that are ready for the modern web.

What are Web Components?

Web Components are a set of W3C standards that allow you to create new, reusable, and encapsulated custom elements to use in web pages and web applications. Think of them as building blocks that come with their own logic and styling, so you don't have to worry about them conflicting with the rest of your site.

There are three main technologies that form the foundation of Web Components:

  • Custom Elements: A JavaScript API that allows you to define a new HTML tag, like <my-button>, and its behavior.
  • Shadow DOM: A way to attach a hidden, separate DOM tree to an element. This creates a "shadow" for the component, ensuring its styles and scripts don't leak out and affect the main page, and vice versa.
  • HTML Templates: The <template> and <slot> tags allow you to write reusable markup that is not rendered on the page until it's activated.

💡 Why Use Web Components?

They promote code reuse, solve CSS and JavaScript conflicts through encapsulation, and allow for a clean separation of concerns. They are framework-agnostic and work in any modern browser.

Creating a Simple Web Component

Let's walk through an example of creating a simple custom element called <hello-world>. The key is to define a class that extends HTMLElement and then use customElements.define() to register it.

Step 1: Define the JavaScript Class

class HelloWorldComponent extends HTMLElement {
  constructor() {
    super();
  }
  
  connectedCallback() {
    this.innerHTML = `<h1>Hello from a Web Component!</h1>`;
  }
}

Step 2: Register the Element

customElements.define('hello-world', HelloWorldComponent);

Step 3: Use the Component in HTML

<hello-world></hello-world>
Live Example:

Using Shadow DOM for Encapsulation

For more complex components, you'll want to use the Shadow DOM to ensure styles and behavior are self-contained. The styles you write inside the Shadow DOM will not affect anything outside of your component.

class EncapsulatedComponent extends HTMLElement {
  constructor() {
    super();
    // Attach a shadow DOM to the custom element
    const shadow = this.attachShadow({ mode: 'open' });
    
    // Add styles and HTML to the shadow DOM
    shadow.innerHTML = `
      <style>
        h3 {
          color: purple;
          font-family: sans-serif;
        }
      </style>
      <h3>I am encapsulated!</h3>
      <p>My styles will not affect anything outside of this component.</p>
    `;
  }
}
customElements.define('encapsulated-component', EncapsulatedComponent);

Advanced: Slots for Dynamic Content

The <slot> element is a powerful tool for creating flexible components. It acts as a placeholder for content that you provide from the outside.

class CardComponent extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `
      <style>
        .card {
          border: 1px solid gray;
          padding: 16px;
          border-radius: 8px;
          box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
      </style>
      <div class="card">
        <slot>Default Content</slot>
      </div>
    `;
  }
}
customElements.define('my-card', CardComponent);

Using the Card with a Slot

<my-card>
  <h3>This is the Card Title</h3>
  <p>This content is placed inside the slot.</p>
</my-card>