Web Components: Building Custom Elements with JavaScript

Web components are a powerful tool for building reusable and encapsulated UI elements in web applications. They allow developers to create custom elements with their own markup, style, and behavior, which can be easily reused across different projects and shared with other developers. In this article, we will explore the fundamentals of web components and learn how to build custom elements using JavaScript.

What are Web Components?

Web components are a set of web platform APIs that allow you to create reusable, encapsulated, and composable UI elements. They consist of three main specifications: Custom Elements, Shadow DOM, and HTML Templates.

Custom Elements

Custom Elements provide a way to define your own HTML elements with custom behaviour. By creating new elements, you can extend existing HTML elements or create entirely new ones. Custom Elements enable you to encapsulate the implementation details of your elements and provide a clean API for using them.

To define a custom element, you need to create a new class that extends the base HTMLElement class. Let's create a simple custom element called "my-element" that displays a greeting message:

<!DOCTYPE html>
<html>
<head>
    <title>Custom Elements Example</title>
</head>
<body>
    <my-element></my-element>

    <script>
        class MyElement extends HTMLElement {
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });
                const paragraph = document.createElement('p');
                paragraph.textContent = 'Hello, Web Components!';
                this.shadowRoot.appendChild(paragraph);
            }
        }

        customElements.define('my-element', MyElement);
    </script>
</body>
</html>

In the code above, we define the class MyElement that extends HTMLElement. In the constructor, we create a shadow root using the attachShadow method. Then, we create a <p> element, set its text content to "Hello, Web Components!", and append it to the shadow root.

Hello, Web Components!

Shadow DOM

Shadow DOM allows you to encapsulate the markup and style of your custom elements. It provides a scoped DOM subtree that is attached to a regular HTML element. This allows you to create components with their own encapsulated styles, preventing conflicts with styles in the rest of the document.

Let's enhance our custom element to include a styled button using Shadow DOM:

<!DOCTYPE html>
<html>
<head>
    <title>Shadow DOM Example</title>
</head>
<body>
    <my-element></my-element>

    <script>
        class MyElement extends HTMLElement {
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });
                
                const paragraph = document.createElement('p');
                paragraph.textContent = 'Hello, Web Components!';
                this.shadowRoot.appendChild(paragraph);

                // Create a button element
                const button = document.createElement('button');
                button.textContent = 'Click me';
                button.addEventListener('click', () => {
                    alert('Button clicked!');
                });

                // Apply styles to the button
                const style = document.createElement('style');
                style.textContent = `
                    button {
                        background-color: #007bff;
                        color: white;
                        padding: 10px 20px;
                        border: none;
                        border-radius: 4px;
                        cursor: pointer;
                    }
                    button:hover {
                        background-color: #0056b3;
                    }
                `;

                // Append the button and style to the shadow root
                this.shadowRoot.appendChild(button);
                this.shadowRoot.appendChild(style);
            }
        }

        customElements.define('my-element', MyElement);
    </script>
</body>
</html>

In the updated code, we create a button element and define its styles using the style element. By appending the button and style to the shadow root, the styles will only apply to the custom element, ensuring encapsulation.

Hello, Web Components!
[Click me] (styled blue button)

HTML Templates

HTML Templates provide a way to define reusable chunks of markup that can be cloned and inserted into the DOM. Templates can contain any valid HTML content and can be dynamically populated with data. They are especially useful for creating instances of custom elements.

Let's modify our custom element to use an HTML template for its content:

<!DOCTYPE html>
<html>
<head>
    <title>HTML Templates Example</title>
</head>
<body>
    <template id="my-element-template">
        <style>
            p {
                font-size: 18px;
                color: #333;
                font-weight: bold;
            }
            button {
                background-color: #28a745;
                color: white;
                padding: 8px 16px;
                border: none;
                border-radius: 4px;
                cursor: pointer;
            }
        </style>
        <p>Hello, Web Components with Templates!</p>
        <button>Template Button</button>
    </template>

    <my-element></my-element>

    <script>
        class MyElement extends HTMLElement {
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });

                // Get the template content
                const template = document.getElementById('my-element-template').content;

                // Clone the template content and append it to the shadow root
                const clone = document.importNode(template, true);
                this.shadowRoot.appendChild(clone);
                
                // Add event listener to the button
                this.shadowRoot.querySelector('button').addEventListener('click', () => {
                    alert('Template button clicked!');
                });
            }
        }

        customElements.define('my-element', MyElement);
    </script>
</body>
</html>

In the updated code, we retrieve the content of an HTML template element with the ID "my-element-template". We then clone the template content using document.importNode() and append it to the shadow root. This allows us to define the custom element's content within the template, providing more flexibility and reusability.

Hello, Web Components with Templates!
[Template Button] (styled green button)

Key Benefits

Feature Benefit Use Case
Custom Elements Create reusable components Custom widgets, UI libraries
Shadow DOM Style encapsulation Preventing CSS conflicts
HTML Templates Declarative markup Complex component structures

Browser Compatibility

Web Components are supported in all modern browsers including Chrome, Firefox, Safari, and Edge. For older browsers, polyfills are available to ensure compatibility.

Conclusion

Web components provide a powerful mechanism for building reusable and encapsulated UI elements using Custom Elements, Shadow DOM, and HTML Templates. They enable better code organization, style isolation, and component reusability across different projects and frameworks.

Updated on: 2026-03-15T23:19:01+05:30

593 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements