Lifecycle Callbacks
Custom elements are not just inert tags — they have a lifecycle. The browser calls specific methods on your class at well-defined moments: when the element is created, when it is inserted into the document, when its attributes change, and when it is removed. Handling these moments correctly is the foundation of a well-behaved custom element.
This module covers four lifecycle callbacks:
constructor— element is created (class instantiated)connectedCallback— element is inserted into a documentattributeChangedCallback— an observed attribute is added, changed, or removeddisconnectedCallback— element is removed from a document
It also covers upgrading — what happens when the browser encounters a custom element tag before the class is registered.
Lifecycle sequence
Section titled “Lifecycle sequence”flowchart LR C["constructor (element created)"] CC["connectedCallback (inserted into DOM)"] AC["attributeChangedCallback (attribute changed) — fires each time —"] DC["disconnectedCallback (removed from DOM)"] C --> CC CC --> AC AC --> AC CC --> DC
| Callback | When it fires |
|---|---|
constructor | Element is instantiated — via new or HTML parsing |
connectedCallback | Element is inserted into any document (or shadow root) |
attributeChangedCallback | An observed attribute is set, changed, or removed |
disconnectedCallback | Element is removed from the document |
The attributeChangedCallback can fire multiple times — once per attribute change — and it fires both before and after the element is connected depending on when attributes are set.
Upgrading existing elements
Section titled “Upgrading existing elements”If the browser encounters <my-widget> in the HTML before the class is registered, it creates a plain HTMLElement first. When customElements.define('my-widget', MyWidget) is later called, the browser upgrades those elements by running their constructor and, if they are already in the DOM, their connectedCallback. You can await an upgrade with customElements.whenDefined('my-widget').
Live demo
Section titled “Live demo”The element below logs each lifecycle event it observes. Click Remove element to trigger disconnectedCallback, then re-add it to see connectedCallback fire again.