[JS] document.defineElement | custom HTML elements without a hypen
Tags: discuss, javascript
Published: 2018-04-12 18:33:02

---
title: [JS] document.defineElement | custom HTML elements without a hypen
published: true
description: GitHub package document.defineElement is a polyfill for document.registerElement that works in all browsers and does not require a hypen in the nodename. Good or bad idea? Elaborate.
tags: discuss, javascript
cover_image: https://thepracticaldev.s3.amazonaws.com/i/uhhv7dvcj3wyiaut9y2c.gif
---

GitHub package [document.defineElement](https://github.com/jochemstoel/document.defineElement) is a polyfill for document.registerElement that does not require a hypen in the nodename. This enables you to register _&lt;thing&gt;&lt;/thing&gt;_ in stead of _&lt;x-thing&gt;&lt;/x-thing&gt;_.

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.

```js 
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 */
```

```js
/* or you can do this too */
var Custom = document.defineElement('custom-element', HTMLSomeCustomElement)
document.body.appendChild(new Custom())
``` 

```js
/* 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.

```js
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)
``` 

```markup
<body>
	<clock></clock>
</body>
``` 

![Clock Example GIF image](https://thepracticaldev.s3.amazonaws.com/i/uhhv7dvcj3wyiaut9y2c.gif)

> 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