DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Create Custom HTML Element With customElements.define()
Ashja
Ashja

Posted on

Create Custom HTML Element With customElements.define()

So, i developed angular application about a month ago, and i wondered why in angular app the element name is unique and different with HTML element, and the element will still unique even in build release.

Today when i read Javascript Notes For Professionals (it is a book writen by GoalKicker group, you can download it here), i saw something that took my interest, "Chapter 51: Custom Elements".

That chapter explains about creating custom element with document.registerElement() which is already deprecated. So, i searched for another method, and here is what i found.

1. What We Will Build

A simple timer element named app-timer with red background, of course we will build it as custom element.

2. Code

We will use customElements.define() method in this post, because it's the recommended way to define custom element in modern javascript.
Create an index.html file and paste these codes:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Custom Element Example</title>
</head>

<body>
    <script>
        class Timer extends HTMLElement {
            constructor() {
                super()
            }
        }
        customElements.define('app-timer', Timer)
    </script>
    <app-timer/>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Okay let's explain it one by one

First, we create Timer class that extends HTMLElement class, then we define the constructor method with nothing inside it except executing super method.

Then, we call define method from customElements class with "app-timer" and Timer class as its argument, "app-timer" is element tag name (like body, footer, head) and Timer class is element handler class.

Please note that element tag name should include a hypen(-), "x-footer" and "my-element" is a valid element tag name while "myblock" and "header_block" is not.

Then let's run this html file in browser.
Nothing here

Yep, there's nothing here, because we haven't add anything into the custom element, it would be scary if there is something shown in the page.

Add timer functionality to constructor method, so it will looks like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Custom Element Example</title>
</head>

<body>
    <script>
        class Timer extends HTMLElement {
            constructor() {
                super()
                const shadow = this.attachShadow({mode:"open"})
                shadow.innerHTML = "1"
                setInterval(()=>{
                    shadow.innerHTML = parseInt(shadow.innerHTML) + 1
                }, 1000)
            }
        }
        customElements.define('app-timer', Timer)
    </script>
    <app-timer/>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

And again, let's explain things line by line

const shadow = this.attachShadow({mode:"open"})
Enter fullscreen mode Exit fullscreen mode

we define shadow constant with value returned from attachShadow() method. attachShadow() used to get our custom element DOM property, we can't access the property directly, it will throws error.

shadow.innerHTML = "1"
Enter fullscreen mode Exit fullscreen mode

You must be familiar with this code, yep, we add text to element's innerHTML.

setInterval(()=>{
    shadow.innerHTML = parseInt(shadow.innerHTML) + 1
}, 1000)
Enter fullscreen mode Exit fullscreen mode

Increase value of custom element's innerHTML by 1 every second.

Ok try to run it and you won't see blank page anymore.
Basic Timer

And that's it, we have added timer functionality to custom element.

Is it enough? No

Don't forget about the red background part, we must add style to this custom element. We will place the code that change element style in connectedCallback() method. This method executed after the Element is rendered, so we won't face DOM issues.

class Timer extends HTMLElement {
    constructor() {
        super()
        const shadow = this.attachShadow({mode:"open"})
        shadow.innerHTML = "1"
        setInterval(()=>{
            shadow.innerHTML = parseInt(shadow.innerHTML) + 1
        }, 1000)
    }
    connectedCallback(){
        this.style.backgroundColor = "red"
        this.style.padding = "10px"

    }
}
customElements.define('app-timer', Timer)
Enter fullscreen mode Exit fullscreen mode

You can do anything in connectedCallback() method, manipulating DOM, rendering, there is no restriction. Ok, time to test our app again.
Finished

And as you can see, the app-timer element background color turns into red, i even added padding for beautifier. You can try it by your own on the codesandbox below.

References

  • Javascript Notes for Professionals
  • Google Developers Custom Element Docs
  • Some StackOverflow Thread

Thanks to Tranmautritam in Pexels for their beautiful picture (the picture i used in banner).

Top comments (0)

Take a look at this:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. πŸ›