Crafting Your Own HTML: A Guide to Custom Elements

Nehal JainNehal Jain
8 min read

Let's embark on an exciting journey to create our very first custom HTML element! ๐Ÿš€

Introduction:

What the heck is Custom Element?

Custom elements are like building blocks for the web, allowing you to create unique and powerful components that go beyond the standard HTML elements. Unlike the ad-hoc solutions of the past, custom elements provide a structured way to define new elements and their behavior, making them a valuable tool for modern web development. ๐Ÿ› ๏ธ

What is Web Components?

Web Components is a powerful suite of technologies that empowers you to create reusable custom elements. These elements come with their functionality encapsulated, ensuring they remain isolated from the rest of your code. This encapsulation allows you to seamlessly integrate these custom elements into your web apps, enhancing modularity and maintainability. Dive into the world of Web Components and revolutionize the way you build web applications! ๐ŸŒโœจ

Types of Custom Elements: -

Mainly there are two types of custom elements:

  1. Autonomous custom element :
    Autonomous custom elements are like standalone building blocks for your web pages. They're completely independent, not based on any existing HTML element. Think of them as custom-made Lego bricks that you can use to construct unique and interactive components. ๐Ÿงฑ

  2. Customized built-in element :
    Customized built-in elements are like taking a classic Lego brick and giving it a complete makeover. They start with a familiar HTML element as a base, but you can customize their appearance, behavior, and functionality to fit your specific needs. Think of it as creating a unique version of a standard building block. ๐ŸŽจ

Benefits of creating Custom Elements:

Custom elements offer several advantages for web development:

  1. Code Reusability:
  • Custom elements can be encapsulated as reusable components, making your codebase more organized and easier to maintain. ๐Ÿ“ฆ

  • Once created, custom elements can be reused across multiple projects, saving time and effort. โณ

  1. Improved Maintainability:
  • Changes to a custom element's implementation only affect that specific component, minimizing the risk of unintended side effects. ๐Ÿ”ง

  • Issues can be isolated to specific components, simplifying debugging and troubleshooting. ๐Ÿž

There are even more exciting benefits to creating custom elements beyond these. ๐ŸŒŸ

Prerequisites for creating custom elements:

To effectively create custom elements, you'll need a solid foundation in the following:

  1. HTML : Understanding the fundamental structure of HTML documents, including elements, attributes, and content. ๐Ÿ“„

  2. CSS : Understanding how CSS rules cascade and override each other and knowledge of CSS selectors to style custom elements and their components. ๐ŸŽจ

  3. JavaScript:

    • Fundamentals: A strong grasp of JavaScript programming concepts, including variables, data types, functions, and objects. ๐Ÿ’ป

    • DOM manipulation: Ability to interact with the DOM using JavaScript to create, modify, and remove elements. ๐Ÿ—๏ธ

    • Object-oriented programming (OOP): Understanding OOP concepts like classes, objects, inheritance, and encapsulation, which are essential for creating custom elements. ๐Ÿงฉ

Let's start! ๐ŸŽ‰

Creating Custom Elements:

Ready to explore custom elements? Let's get started and create something amazing! ๐ŸŒŸ

Creating an Autonomous Custom Element:

  1. Define Your Custom Element: Start by defining a class for your custom element. This class will extend the HTMLElement class, giving you a foundation to build upon.

     // extending HTMLElement class
     class Car extends HTMLElement{
    
         constructor(){
             super();
    
             // initialize element logic
             this._companyName = null;
         }
     }
    

    observedAttributes static property specifies which attributes to observe for changes.

     // extending HTMLElement class
     class Car extends HTMLElement{
    
         constructor(){
             super();
    
             // initialize element logic
             this._companyName = null;
         }
    
         // adding observed attributes
         static observedAttributes = ["company"];
    
     }
    

    The attributeChangedCallback method is called whenever an attribute is changed.
    connectedCallback method is called when the element is added to the DOM.

     // extending HTMLElement class
     class Car extends HTMLElement{
    
         constructor(){
             super();
    
             // initialize element logic
             this._companyName = null;
         }
    
         // adding observed attributes
         static observedAttributes = ["company"];
    
         // attributeChangedCallback() method is used when attributes is changed 
         attributesChangedCallback(propertyName, oldValue, newValue){
             // propertyName will always be "company" due to observedAttributes
             this._companyName = newValue;
             this._updateRendering();
         }
    
         // connectedCallback() method is used when the element is added to the DOM
         connectedCallback(){
             this._updateRendering();
         }
    
     }
    

    The getter and setter methods allows us to get and set custom attributes.
    and updateRendering method is used to update render method.

    .

    ```javascript // extending HTMLElement class class Car extends HTMLElement{

    constructor(){ super();

    // initialize element logic this._companyName = null; }

    // adding observed attributes static observedAttributes = ["company"];

    // attributeChangedCallback() method is used when attributes is changed attributesChangedCallback(propertyName, oldValue, newValue){ // propertyName will always be "company" due to observedAttributes this._companyName = newValue; this._updateRendering(); }

    // connectedCallback() method is used when the element is added to the DOM connectedCallback(){ this._updateRendering(); }

    // getter and setter methods used to get and set custom attribute. get company() { return this._companyName; } set company(value) { this.setAttribute("company", value); }

_updateRendering(){ // It is for reader. You can check this.ownerDocument.defaultView to see if something // inserted into a document with a browsing context and avoid doing // any work if not. }

}


    .

    .  
    However, it's a good idea to check `this.ownerDocument.defaultView` to ensure that the element has been inserted into a document with a browsing context before proceeding with any operations. This helps avoid unnecessary work

2. **Register Your Custom Element:** To register this class as a custom element, use the `customElements.define` method.

    ```javascript
    // define the custom element
    customElements.define("new-car", Car);
  1. Use Your Custom Element: Now, you can use your custom element just like any other HTML tag.
 <new-car country="ferrari">This is new car.</new-car>

You can also creating new-car element using the DOM API:

// creating using DOM API
const newCar = document.createElement("new-car");
newCar.company = "ferrari";
document.body.appendChild(newCar);

Finally, you can also creating elements using the custom element constructor:

// creating element using custom element constructor
const newCar = new Car();
newCar.company = "ferrari";
document.body.appendChild(newCar);

Creating an Customized built-in Element :

  1. Choose Your Base Element: Start by selecting an existing HTML element that you want to customize. This could be anything from a button to a paragraph.
    Here we take a <button></button> element.

     <button type="button"> We take button element to Customize. </button>
    
  2. Define Your Custom Element: Create a class that extends the chosen HTML element's class. This is where you'll define the unique behavior and appearance of your custom element.
    In our case we take HTMLButtonElement class.

     // extending HTMLButtonElement class
     class ClickableButton extends HTMLButtonElement{
         constructor(){
             super();
    
             // addEventListener() method for clickable button events.
             this.addEventListener("click", () => {
                 // write some clickable events! 
             });
         }
    
     }
    
  3. Register Your Custom Element: Use the customElements.define method to register your new element. Make sure to specify the base element you're extending.
    Here we extending button element.

     // defining the custom element
     customElements.define("clickable-button", ClickableButton, { extends : "button" });
    
  4. Use Your Custom Element: Now, you can use your customized element just like any other HTML tag.

    To construct our customized built-in element from parsed HTML source text, we use the is attribute on a button element:

<button is="clickable-button">Click this Button!</button>

You can also creating clickable-button element using the DOM API:

// creating using DOM API
const clickableButton = document.createElement("button", { is: "clickable-button" });
clickableButton.textContent = "Click this Button!";
document.body.appendChild(clickableButton);

Finally, you can also creating elements using the custom element constructor:

// creating element using custom element constructor
const clickableButton2 = new ClickableButton();
clickableButton2.textContent = "Click this Button!";
document.body.appendChild(clickableButton2);

console.log(clickableButton2.localName); // button (in browser console)

Keep in mind that when you create a customized built-in element , the is attribute won't appear in the DOM because it wasn't explicitly set. However, it will show up in the output when you serialize the element:

// serializing the element
console.log(clickableButton.outerHTML); // <button is="clickable-button">Click this Button!</button>
console.log(clickableButton2.outerHTML); // <button is="clickable-button">Click this Button!</button>

Styling Custom Elements:

Styling custom elements involves applying CSS to enhance the appearance and functionality of your custom HTML components. ๐ŸŽจโœจ

Shadow DOM:

Encapsulation is key for custom elements, ensuring they work seamlessly across any web page without interference. Shadow DOM helps achieve this by attaching a hidden DOM tree to an element, protecting its internals from external JavaScript and CSS.

First, create a custom element and attach a shadow root to it using the attachShadow() method. This will create a new DOM tree, separate from the main document DOM.

class CustomElement extends HTMLElement{
    constructor(){
        super();

        // creating a shadow root for element
        const shadowRoot = this.attachShadow({ mode : "open" });
        shadowRoot.innerHTML = "it is a Shadowed Custom Element.";
    }

}

// defing custom elements
customElements.define("custom-element", CustomElement);

// creating custom element using custom element constructor
const customElement = new CustomElement();
document.body.appendChild(customElement);

Advanced Topics:

Diving into advanced topics on custom elements, such as performance considerations and template literals, can significantly enhance the efficiency and maintainability of your web applications. ๐Ÿš€ Performance considerations are crucial when developing custom elements, as they ensure that your components load quickly and run smoothly. Techniques such as lazy loading, efficient rendering, and minimizing reflows and repaints can help optimize the performance of your custom elements. โšก

Template literals, on the other hand, offer a powerful way to define and manipulate HTML templates within your custom elements. ๐Ÿ“ By using template literals, you can create dynamic and reusable templates that are easy to read and maintain. ๐Ÿ”„

By mastering these advanced topics, you can push the boundaries of what is possible with custom elements, creating web applications that are not only powerful and feature-rich but also performant and maintainable. ๐ŸŒŸ

There are even more exciting ways to create custom elements, such as form-associated elements and with default accessible roles, states, and properties, expanding the possibilities beyond what we've discussed so far. ๐ŸŒŸ

Happy coding! ๐Ÿš€

0
Subscribe to my newsletter

Read articles from Nehal Jain directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nehal Jain
Nehal Jain

| Tech Fanatic ๐Ÿ˜Ž | Sophomore | Learning Web Development & DSA || JavaScript || NodeJS || ExpressJS || And More |