DEV Community 👩‍💻👨‍💻

Cover image for [JS] document.defineElement | custom HTML elements without a hypen
Jochem Stoel
Jochem Stoel

Posted on

[JS] document.defineElement | custom HTML elements without a hypen

GitHub package document.defineElement is a polyfill for document.registerElement that does not require a hypen in the nodename. This enables you to register <thing></thing> in stead of <x-thing></x-thing>.

Of course it doesn't have to be used as a polyfill, you could stick it in your Electron application or whatever.

What is this?

The DOM's document.registerElement requires you to include a hyphen in the node name to prevent conflict. I refused to accept this rule and this is the result.

  • document.defineElement is a polyfill for document.registerElement modified to allow elements without a hyphen (-)
  • document.defineElement works even in browsers that do not implement document.registerElement.
  • document.defineElement is renamed to prevent conflict with document.registerElement.
  • document.defineElement lets you overwrite all existing DOM node behaviors.
  • document.defineElement can be used to create dynamic and interactive HTML node types.

document.defineElement()

Just like document.registerElement, your new class supports the following (optional) callbacks. The following method/syntax is identical to using registerElement and should be pretty straightforward.

class HTMLSomeCustomElement extends HTMLElement {
    /* Fires when an instance of the element is created. */
    createdCallback() {
        /* */
    }

    /* Fires when an instance was inserted into the document. */
    attachedCallback() {
        /* */
    }

    /* Fires when an instance was removed from the document. */
    detachedCallback() {
        /* */
    }

    /* Fires when an attribute was added, removed, or updated. */
    attributeChangedCallback(attr, oldVal, newVal) {
        /* */
    }
}

document.defineElement('custom-element', HTMLSomeCustomElement) 
/* now every <custom-element></custom-element> will be an instanceof HTMLSomeCustomElement */
Enter fullscreen mode Exit fullscreen mode
/* or you can do this too */
var Custom = document.defineElement('custom-element', HTMLSomeCustomElement)
document.body.appendChild(new Custom())
Enter fullscreen mode Exit fullscreen mode
/* or simply this works as well */
document.createElement('custom-element')
Enter fullscreen mode Exit fullscreen mode

Simple clock, an actual example

The following custom element will show the current time and update it every second like a clock. In this example we are not using a hyphen in the node name. All we need to show a clock in our custom interface framework thing is put

<clock></clock>

somewhere.

class HTMLSimpleClockElement extends HTMLSpanElement {

    createdCallback() {
        var self = this
        /* we could do something with this.getAttribute() for instance set interval */
        this.interval = setInterval(function() {
            self.innerText = new Date(new Date().getTime()).toLocaleTimeString()
        }, 1000)
    }

}

document.registerElement('clock', HTMLSimpleClockElement)
Enter fullscreen mode Exit fullscreen mode
<body>
    <clock></clock>
</body>
Enter fullscreen mode Exit fullscreen mode

Clock Example GIF image

You could support some attributes on the clock such as the refresh interval or display string template and then check this.attributes in the created or attached callback function.

Ideas

I am not very imaginative. Sorry.

  • create an <include></include> element that fetches remote content and renders it.
  • design a <chat></chat> element that automatically connects to your WebSocket server
  • something with <user></user> or <like-button></like-button>

Bad ideas

  • completely overwrite the <body> element and break things
  • make iframes or script tags stop working

Top comments (0)

🌚 Browsing with dark mode makes you a better developer.

It's a scientific fact.