HTML Custom Elements
Published: 2023-04-10 18:40:33

HTML custom elements are a game-changing feature that have transformed the way developers create web apps and websites. With custom elements, developers can create their own HTML tags and define their behaviour, properties, and methods. This means that instead of relying on the limited set of default HTML elements, developers can now create custom-made elements tailored to their specific needs. In this blog post, we will explore the world of HTML custom elements, their benefits, and how you can create them. Whether you are a seasoned developer or just starting with HTML, this blog is for you. So, buckle up and let's get started!

Defining your own custom HTML element is easy. We need to use customElements.define function to register our component so browser can understand and render our element.

customElements.define method takes three arguments

Name of your component. (say color-text)
Your component. ( A ES6 class )
An optional object if you are trying to extend another HTML tag
Let’s try to write a custom HTML tag which will render text with different colors.

```
<html>
    <head>
    </head>
    <body>
        <color-text color="red">
            Hello world
        </color-text>
        <color-text color="yellow">
            Hello world
        </color-text>
        <script>
            
                class ColorText extends HTMLElement {
                    constructor () {
                        super()
    
                        const color = this.getAttribute('color')
    
                        const shadowDOM = this.attachShadow({ mode: 'open' })
    
                        const text = document.createElement('p')
                        text.innerHTML = this.innerHTML
                        this.innerHTML = ''
                        
                        const style = document.createElement('style')
                        style.innerHTML = `p { color: ${color} }`
    
                        shadowDOM.appendChild(style)
                        shadowDOM.appendChild(text)
    
                    }
                }
    
                customElements.define('color-text', ColorText)
            </script>
    </body>
</html>
```
The color-text element takes one attribute color and according to that, it changes the font color of text written inside it.

If we run color-text.html in your browser we will see color-text in action


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rb8cps09dlmp4lnmajm9.png)


Let’s have a look at what is exactly happening here

```
<script>

    class ColoredText extends HTMLElement {
        constructor () {
            super()

            const color = this.getAttribute('color')

            const shadowDOM = this.attachShadow({ mode: 'open' })

            const text = document.createElement('p')
            text.innerHTML = this.innerHTML
            this.innerHTML = ''

            const style = document.createElement('style')
            style.innerHTML = `p { color: ${color} }`

            shadowDOM.appendChild(style)
            shadowDOM.appendChild(text)

        }
    }

    customElements.define('color-text', ColorText)
</script>
```

In this snippet, we are defining a new class ColoredText which extends HTMLElement. We are not going to go deep in this but you should know that HTMLElement class provides our custom element will all of the things it needed to run in the browser like lifecycle hooks and other bindings.

We have our constructor and inside it, we are calling super() which calls HTMLElement constructor ( again we don’t have to focus on this ) after that we are extracting color attribute passed to color-text and storing it inside the color variable. So whatever attribute you pass to color-text it will be accessible using this.getAttribute method.

In the next line, we are creating a Shadow Dom. The reason behind this is this is a custom HTML component and its HTML and CSS style should be scoped to only this element. That means its Markup or CSS style should not affect anything outside it.

After creating the Shadow Dom we created a paragraph element to display text passed to color-text inside the browser. In the next line we set paragraph innerHTML to be equal to innerHTML of color-text element. That means paragraph innerHTML will be replaced by whatever is written between <color-text></color-text>

We are setting this.innerHTML to empty because we if we don’t it will show “Hello world” which we don’t want. We want our custom element to show “Hello world” wrapped inside a paragraph tag.

Next up we create a style element and inside it, we set the color of paragraph tag to be the same as color passed to color-text i.e. “red” or “yellow”

And in the end, we append both our style and paragraph element to our Shadow DOM.

We are all set just one thing is remaining and that is registering our component so the browser can find out what to render when it encounters color-text in our markup. We do that by calling customElements.define(‘color-text’, ColoredText)

You can see we are using our custom HTML component color-text here

```
<color-text color="red">
    Hello world
</color-text>
<color-text color="yellow">
    Hello world
</color-text>
```
And it works perfectly fine. Firstly we pass color as red so the browser renders “Hello world” in red and second time we pass yellow and browser renders “Hello world” in yellow.

What would you do with these custom HTML elements?
I personally like them. Still, they are no match for a library like React or Angular but having First class support of custom Elements without the need of any external dependencies open a lot of opportunity for vanilla Javascript applications. It also will help us to write more reusable HTML.

Stay tuned for the next part
In the next part, I will be explaining how to use lifecycle hooks.

keep sharing!