This article needs a technical review. How you can help.

This article needs an editorial review. How you can help.

This is an experimental technology
Because this technology's specification has not stabilized, check the compatibility table for usage in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers as the specification changes.

Custom Elements is a capability for creating your own custom HTML tags and elements. They can have their own scripted behavior and CSS styling. They are part of Web Components but they can also be used by themselves.

Note: This is an experimental technology. An complete overhaul of Custom Elements will happen in the standard bodies in 2016. It is unlikely that the outcome will be compatible with current drafts: you'll have to adapt anything you build with them.

You might wonder why this new Custom Elements capability was created, because you could already create a tag name like <mytag> and style it with CSS, and use scripting to attach behaviors to it. One of the reasons to use Custom Elements is that you can use lifecycle callbacks (reactions), which enable you to attach behaviors to different parts of the new element's "lifecycle." For example, you can attach a certain behavior when the element is inserted into the DOM, and a different behavior when it is removed from the DOM.

The key enabler of v1 custom elements is the customElements.define() method (which supersedes Document.registerElement() from the v0 spec). You use this method to register your new element with the browser. The new element uses the HTMLElement interface by default. (If you create a new tag like <mytag> and do not register it, it uses the HTMLUnknownElement interface.) You can also base a custom element on a native element like <button> (although if you do this, you cannot use a custom tag name like <my-button>, you must use a syntax like <button is="my-button">).

Lifecycle callbacks

You can use the following lifecycle callbacks with custom elements:

  • constructor - The behavior you define occurs when the element is created or upgraded.
  • connectedCallback - Called when the element is inserted into the DOM.
  • disconnectedCallback - Called when the element is removed from the DOM.
  • attributeChangedCallback(attrName, oldVal, newVal) - The behavior occurs when an attribute of the element is added, changed, or removed, including when these values are initially set.


Custom Elements can be created using Object.prototype and ShadowRoot techniques, as in this jsfiddle (which uses the old, v0, document.registerElement() call):

Another simpler way to build Custom Elements in Ecmascript 2015 is using "Class" instead of "ProtoType", you can also avoid using the "ShadowRoot".

The HTML file:

If nothing appeared below, then your browser not supporting Custom Elements.
<x-product data-name="Ruby" data-img="" data-url=""></x-product>
<x-product data-name="JavaScript" data-img="" data-url=""></x-product>
<x-product data-name="Python" data-img="" data-url=""></x-product>

The JS file:

// Create a new object based of the HTMLElement prototype
var XProductProto = Object.create(HTMLElement.prototype);

// Set up the element.
XProductProto.createdCallback = function() {
    // Create a Shadow Root
    var shadow = this.createShadowRoot();

    // Create a standard img element and set it's attributes.
    var img = document.createElement('img');
    img.alt = this.getAttribute('data-name');
    img.src = this.getAttribute('data-img');
    img.width = '150';
    img.height = '150';
    img.className = 'product-img';

    // Add the image to the Shadow Root.

    // Add an event listener to the image.
    img.addEventListener('click', function(e) {
        window.location = this.getAttribute('data-url');
    // Create a link to the product.
    var link = document.createElement('a');
    link.innerText = this.getAttribute('data-name');
    link.href = this.getAttribute('data-url');
    link.className = 'product-name';

            // Add the link to the Shadow Root.

// Register the new element.
var XProduct = document.registerElement('x-product', {  // deprecated, use customElements.define() instead
    prototype: XProductProto

The CSS file:

The ::Shadow used below is being deprecated.

body {
  background: #F7F7F7;

x-product {
  display: inline-block;
  float: left;
  margin: 0.5em;
  border-radius: 3px;
  background: #FFF;
  box-shadow: 0 1px 3px rgba(0,0,0,0.25);
  font-family: Helvetica, arial, sans-serif;
  -webkit-font-smoothing: antialiased;

x-product::shadow .product-img {
  cursor: pointer;
  background: #FFF;
  margin: 0.5em;

x-product::shadow .product-name {
  display: block;
  text-align: center;
  text-decoration: none;
  color: #08C;
  border-top: 1px solid #EEE;
  font-weight: bold;
  padding: 0.75em 0;

Below the live example of the above:


Custom Elements is defined in the following specification:

Specification Status Comment
Custom Elements Working Draft  


Document Tags and Contributors

 Contributors to this page: Dan-Dascalescu, stevemao, maybe, Unihedron, hasan3ysf, teoli, andrewrota, markg
 Last updated by: Dan-Dascalescu,