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

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

jochemstoel profile image Jochem Stoel ・2 min read

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 */
/* or you can do this too */
var Custom = document.defineElement('custom-element', HTMLSomeCustomElement)
document.body.appendChild(new Custom())
/* or simply this works as well */
document.createElement('custom-element')

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)
<body>
    <clock></clock>
</body>

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

Posted on Sep 16 '18 by:

jochemstoel profile

Jochem Stoel

@jochemstoel

Pellentesque nec neque ex. Aliquam at quam vitae lacus convallis pulvinar. Mauris vitae ullamcorper lacus. Cras nisi dui, faucibus non dolor quis, volutpat euismod massa. Donec et pulvinar erat.

Discussion

markdown guide