Custom Elements in HTML

Article Banner
Author(s): Ajay Kumar
Published On: 05 Apr 2025

🧩 Custom Elements in HTML

HTML has evolved from a static markup language to a full-fledged platform for building web applications. One of its most powerful features is the ability to define Custom Elements — your very own HTML tags.

✅ What Are Custom Elements?

Custom Elements are a key feature of the Web Components standard — a set of APIs that lets developers create reusable, encapsulated HTML elements with custom behavior.

🧠 Web Components are a suite of technologies (Custom Elements, Shadow DOM, HTML Templates) for building reusable UI components natively in the browser.

For example:


<user-profile name="Alice" age="30"></user-profile>
  

This <user-profile> tag is not part of standard HTML. It's a custom element you can define with specific behavior and UI.

Each custom element typically includes:

  • A JavaScript class that defines its logic and rendering.
  • A unique tag name (must include a hyphen).
  • Optional lifecycle callbacks for reacting to events like insertion into the DOM or attribute changes.

💡 Why Use Custom Elements?

1. Reusability

Encapsulate UI logic and use your element across multiple pages or projects — just like built-in tags.

2. Encapsulation

By using the Shadow DOM, your element’s internal styles and structure are protected from outside interference.

🧠 Shadow DOM is a hidden DOM tree inside an element that isolates markup and styles from the main document, preventing clashes.

3. Zero Dependencies

No need for a JavaScript framework — Custom Elements are built into the browser.

4. Modular Architecture

Just like components in frameworks (React, Vue), Custom Elements promote maintainability and separation of concerns.

📅 When Should You Use Custom Elements?

Use custom elements when:

  • You need reusable UI pieces that can live independently.
  • You’re building framework-agnostic components for multiple teams.
  • You want to encapsulate logic and styles tightly.
  • You’re building a design system or web component library.

Avoid using them if your project is already heavily coupled to a frontend framework — unless interoperability is a goal.

🛠️ How to Create Custom Elements (Step-by-Step)

Let’s build a simple, interactive custom element: <user-profile>.

🔹 Step 1: Define the Element Class


class UserProfile extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.render();
  }

  static get observedAttributes() {
    return ['name', 'age'];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    this.render();
  }

  render() {
    const name = this.getAttribute('name') || 'Unknown';
    const age = this.getAttribute('age') || 'N/A';

    this.shadowRoot.innerHTML = `
      <style>
        .profile {
          font-family: sans-serif;
          padding: 1em;
          border: 1px solid #ccc;
          border-radius: 8px;
          background: #f9f9f9;
        }
      </style>
      <div class="profile">
        <h2>${name}</h2>
        <p>Age: ${age}</p>
      </div>
    `;
  }
}
  
Code Sample #1 : Defining the Element Class

🧠 Lifecycle Callbacks like attributeChangedCallback fire at different stages of the element's life (e.g., insertion or attribute change).

🔹 Step 2: Register the Custom Element


customElements.define('user-profile', UserProfile);
  
Code Sample #2 : Registering the Custom Element

🧠 Custom element tag names must include a hyphen to differentiate them from standard HTML tags.

🔹 Step 3: Use It in HTML


<user-profile name="Jane Doe" age="28"></user-profile>

<script src="user-profile.js"></script>
  
Code Sample #3 : Using it in HTML

Custom Element in Action
Figure 1 : Custom Element in Action

🎯 Bonus: Make It Interactive

Let’s enhance it with a birthday button to increment the age.


render() {
  const name = this.getAttribute('name') || 'Unknown';
  const age = this.getAttribute('age') || 'N/A';

  this.shadowRoot.innerHTML = `
    <style>
      .profile { font-family: sans-serif; }
      button { margin-top: 10px; }
    </style>
    <div class="profile">
      <h2>${name}</h2>
      <p>Age: <span id="age">${age}</span></p>
      <button id="birthdayBtn">Celebrate Birthday 🎂</button>
    </div>
  `;

  this.shadowRoot.querySelector('#birthdayBtn').onclick = () => {
    let newAge = parseInt(this.getAttribute('age') || '0') + 1;
    this.setAttribute('age', newAge.toString());
  };
}
  
Code Sample #4 : Making It Interactive

Interactive custom element in action
Figure 2 : Interactive custom element in action

⚠️ Gotchas to Keep in Mind

Gotcha Why It Matters What You Should Do
Tag name must include a hyphen Avoids conflicts with native HTML tags Always use names like my-button, user-profile
Shadow DOM may block external CSS Styles in global CSS files won’t reach inside Define styles inside the shadow DOM or use CSS variables
Not supported in older browsers (e.g., IE11) Your users might see broken UI Use polyfills or feature detection if backward compatibility is required
No data binding or templating out of the box You may miss convenience features from frameworks Consider adding a light templating engine or integrate with frameworks carefully
Observed attributes must be explicitly listed Your component won't react to attribute changes otherwise Always declare observedAttributes properly to enable dynamic updates

📦 Packaging Tips

  • Bundle your custom elements using Vite, Rollup, or Webpack for modular usage.
  • You can publish them to npm or host via CDN for global use.
  • Prefix your components (my-, app-, etc.) to avoid name collisions.

📚 Summary

Concept Description
What Custom HTML tags with built-in behavior
Why Reusable, encapsulated, framework-free components
When For UI modules that are reused or shared
How Define a class, use customElements.define, and drop in your HTML

🚀 Final Thoughts

Custom Elements are a native way to bring component-based architecture to your frontend without the weight of a framework. They offer reusability, encapsulation, and portability across projects.

They’re a perfect fit when building reusable UI pieces, design systems, or standalone widgets. Try one today — you’ll appreciate how clean and maintainable your frontend can be.

Copyright © 2025 Dev Codex

An unhandled error has occurred. Reload 🗙