Can I create a custom element based on a native element?

posted on

Back to overview

Yes, but it’s implemented in all major browsers except Safari, which has no plan to support it.

Usually, when you write the constructor class for a Web Component you extend it from HTMLElement:

class EnhancedButton extends HTMLElement { }

You can also extend from a native HTML element to gain all its features (DOM properties, methods, accessibility).
To do that, you have to do three things:

Pick the correct DOM interface and extend from it instead of HTMLElement.

class EnhancedButton extends HTMLButtonElement { }

In the define() function, pass a third parameter that specifies which element you're extending.

customElements.define('enhanced-button', EnhancedButton, {extends: 'button'});

Use the new button variation.

<button is="enhanced-button">Click</button>

or

let button = document.createElement('button', {is: 'enhanced-button'});
button.textContent = 'Click';

or

let button = new EnhancedButton();
button.textContent = 'Click';

Here's an example:

class EnhancedButton extends HTMLButtonElement {
  constructor() {
    super();

    this._expanded = false;
    this.setAttribute('aria-expanded', this._expanded);
    this.addEventListener('click', this._toggle);
  }

  _toggle()  {
    this._expanded = !this._expanded
    this.setAttribute('aria-expanded', this._expanded);
  }
}

customElements.define('enhanced-button', EnhancedButton, {extends: 'button'});
Extending from the HTMLButtonElement DOM interface. The enhanced button toggle aria-expanded on click.
<button is="enhanced-button">Yo</button>
<div hidden>Yo!</div>
Turning a regular button into an enhanced button.
[is="enhanced-button"][aria-expanded="true"] + [hidden] {
  display: block;
}
Show the next element sibling if aria-expanded is true.

Back to overview