"Web Components" and "Custom elements" are often mixed up, and web searches for the title of this question don't yet produce much clarity. Let's fix that.

1 Answer 1


Custom elements are a specification part of the Web Components standard, along with Shadow DOM, Templates and HTML imports.

From the spec:

Custom elements provide a way for authors to build their own fully-featured DOM elements. Although authors could always use non-standard elements in their documents, with application-specific behaviour added after the fact by scripting or similar, such elements have historically been non-conforming and not very functional. By defining a custom element, authors can inform the parser how to properly construct an element and how elements of that class should react to changes.


The specification is now at v1. The previous version, v0, had been supported since Chrome 33, and had a different API, using document.registerElement - which is now deprecated.


Custom elements can either be autonomous (creating a new element from scratch (that is, extending HTMLElement), or can customize an existing HTML element (such as HTMLButtonElement).

// autonomous element
customElements.define("flag-icon", FlagIcon);
// customized <button> element
customElements.define("plastic-button", PlasticButton, { extends: "button" });

The second parameter to the customElements.define() call is the name of the class implementing the behavior of the element. See the examples in the spec for autonomous elements and for customized built-in elements.

class PlasticButton extends HTMLButtonElement {
  constructor() {

    this.addEventListener("click", () => {
      // Draw some fancy animation effects!

Custom elements are supported natively in some modern browsers, and can be polyfilled for older browsers going back to Safari 7+ and IE11. See also the v1 polyfill.

Templates and Shadow DOM

By using Templates and Shadow DOM in a custom element, you can make the element easier to handle and resusable.

Templates allow using HTML to declare the structure of custom elements:

<!-- Template Definition -->
<template id="fancy-element-template">
  <div id="container">
    <p>Some fancy markup goes here...</p>

<!-- Custom Element usage -->

Shadow DOM allows styles, ids and classes of the content to be scoped to itself. This prevents CSS bleeding or access to the custom element's internals from outside it.

customElements.define('fancy-element', class extends HTMLElement {
  constructor() {
    let shadowRoot = this.attachShadow({mode: 'open'});
    const t = document.querySelector('#fancy-element-template');
    const instance = t.content.cloneNode(true);

Learn more

Google Developers articles:


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.