> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/component/custom-element/upgrade.md).

# Element Upgrades

[Web Components](/web/component.md) ⟩ [Custom Elements](/web/component/custom-element.md) ⟩

{% tabs %}
{% tab title="👉 相關" %}

* [\<time-formatted>](/web/component/examples/less-than-time-formatted-greater-than.md) - example
* [tagName vs. nodeName](/web/browser/dom/type/node/tagname-vs.-nodename.md)
  {% endtab %}

{% tab title="📘 手冊" %}

* Google ⟩ [Custom Element Upgrades](https://developers.google.com/web/fundamentals/web-components/customelements#upgrades)
* MDN ⟩&#x20;
  * Element ⟩&#x20;
    * [tagName](https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName): string
    * [localName](https://developer.mozilla.org/en-US/docs/Web/API/Element/localName): [DOMString](https://developer.mozilla.org/en-US/docs/Web/API/DOMString)
  * Node ⟩&#x20;
    * [nodeName](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName): [DOMString](https://developer.mozilla.org/en-US/docs/Web/API/DOMString)
      {% endtab %}

{% tab title="🗣 討論" %}

* StackOverflow ⟩ [What is the best way to get an element's tag name in JS?](https://stackoverflow.com/questions/2751556/what-is-the-best-way-to-get-an-elements-tag-name-in-js)
  {% endtab %}
  {% endtabs %}

{% hint style="info" %}

* Custom elements can be used **before** their definition is **registered**.
* The process of calling **customElements.define()** and endowing an **existing element** with a **class definition** is called "**element upgrades**".\
  📘 Google ⟩ [Element Upgrades](https://developers.google.com/web/fundamentals/web-components/customelements#upgrades)
  {% endhint %}

If browser encounters **\<custom-element>** before **customElements.define()**, the element is yet [**unknown**](https://developers.google.com/web/fundamentals/web-components/customelements#unknown), just like any **non-standard tag**. [**Undefined elements**](https://developers.google.com/web/fundamentals/web-components/customelements#unknown) can be styled with CSS selector[**`:not(:defined)`**](/web/css/selectors/pseudo-class.md).

When **customElement.define()** is called, they are “**upgraded**”: a new instance of **CustomElement** is created for each, and **`connectedCallback`** is called. They become **`:defined`**. \
:point\_right: [pseudo-class](/web/css/selectors/pseudo-class.md)

## .whenDefined()

{% hint style="info" %}
To know when a **tag name** becomes **defined**, you can use **customElements.whenDefined()**. It returns a **Promise** that resolves when the element becomes defined.
{% endhint %}

{% tabs %}
{% tab title="whenDefined()" %}

```javascript
customElements.whenDefined('custom-element').then(() => {
  console.log('custom-element defined');
});
```

{% endtab %}

{% tab title="Promise" %}

```javascript
<share-buttons>
  <social-button type="twitter"><a href="...">Twitter</a></social-button>
  <social-button type="fb"><a href="...">Facebook</a></social-button>
  <social-button type="plus"><a href="...">G+</a></social-button>
</share-buttons>


<script>
// Fetch all the children of <share-buttons> that are not defined yet.
let undefinedButtons = buttons.querySelectorAll(':not(:defined)');

let promises = [...undefinedButtons].map(socialButton => {
  return customElements.whenDefined(socialButton.localName);
});

// Wait for all the social-buttons to be upgraded.
Promise.all(promises).then(() => {
  // All social-button children are ready.
});
</script>
```

{% endtab %}
{% endtabs %}
