Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

Web Component Limitations

Jan Miksovsky edited this page Oct 20, 2016 · 3 revisions

Checklist » Web Component Limitations

This page attempts to capture limitations of the current web component APIs that make it difficult or impossible to create a web component that's as good as a standard HTML element.

Some element aspects must be set through attributes during initialization

The Requirements for custom element constructors dictate that a constructor may not add attributes to a new element. Since standard HTML elements created with document.createElement() never have attributes, the expectation is that custom elements shouldn't either. However, there are situations in which a custom element can accomplish a desired result only through adding attributes to itself.

The canonical example here might be ARIA support, which is strictly managed through attributes. A list-like custom element might want to provide a default ARIA role by setting role="listbox" on itself during initialization. However, per the above rules, this cannot be done in the constructor:

class ListBox extends HTMLElement {
  constructor() {
    super();
    this.setAttribute('role', 'listbox'); // This throws an exception.
  }
}

The next-best way to handle this situation might be a connectedCallback.

class ListBox extends HTMLElement {
  connectedCallback() {
    this.setAttribute('role', 'listbox');
  }
}

However, this is suboptimal, for two reasons.

  1. It's surprising that the element will magically gain an attribute when it's added to the document.
  2. The above code can easily overwrite attributes that were added to the element after it was constructed and before it was added to the document:
class ListBox extends HTMLElement {
  connectedCallback() {
    this.setAttribute('role', 'listbox');
  }
}

let listBox = document.createElement('basic-list-box');
listBox.setAttribute('role', 'tabs'); // Set custom role
document.body.appendChild(listBox); // connectedCallback will overwrite role!

To avoid this problem, a custom element should check if it an attribute has already been set before applying a default value:

class ListBox extends HTMLElement {
  connectedCallback() {
    if (!this.getAttribute('role')) {
      this.setAttribute('role', 'listbox');
    }
  }
}

let listBox = document.createElement('basic-list-box');
listBox.setAttribute('role', 'tabs'); // Set custom role
document.body.appendChild(listBox); // connectedCallback leaves role alone
Clone this wiki locally