Skip to content

Defining an Element

Every autonomous custom element starts as an ES class that extends HTMLElement:

class HelloBadge extends HTMLElement {
// lifecycle callbacks go here
}

The class can be anonymous or named — the name is only used internally by JavaScript. The public identity of the element is the tag name you register.

The customElements.define method takes two required arguments and one optional argument:

customElements.define(tagName, constructor, options);
// ^string ^class ^optional { extends: '...' }
customElements.define('hello-badge', HelloBadge);

After this call, the browser knows that every <hello-badge> in the document is an instance of HelloBadge.

Custom element tag names must contain at least one hyphen. This is how the browser distinguishes your elements from current and future built-in elements:

<!-- valid custom element names -->
<hello-badge></hello-badge>
<my-app></my-app>
<x-button></x-button>
<!-- INVALID — no hyphen — the browser treats these as unknown built-ins -->
<hellobadge></hellobadge>
<mybadge></mybadge>

Reserved prefixes you cannot use: annotation-xml, color-profile, font-face, font-face-*.

Once defined, the element works like any native element — place it in markup, set attributes, query it with JavaScript:

<hello-badge name="Alice"></hello-badge>
<hello-badge name="Bob"></hello-badge>
const badge = document.querySelector('hello-badge');
badge.getAttribute('name'); // 'Alice'

Try changing the name attribute value in the HTML panel and watch the output update.

Which tag name is a valid autonomous custom element name?
What is the first argument to customElements.define?
What does the browser do when it encounters a tag name that has been registered with customElements.define?