Understanding connectedCallback in Custom Elements
This article explains the purpose, timing, and practical
implementation of the connectedCallback lifecycle method in
JavaScript Web Components. You will learn how this method functions when
an element is inserted into the Document Object Model (DOM), what tasks
should be performed within it, how it compares to the constructor, and
how to avoid common pitfalls when building custom elements.
What is connectedCallback?
The connectedCallback is one of the standard lifecycle
hooks defined in the Custom Elements specification. It automatically
fires each time a custom element is appended into a document-connected
DOM tree.
Unlike the class constructor(), which only runs once
when the element is instantiated in memory,
connectedCallback executes whenever the browser attaches
the node to the active document.
When Does It Trigger?
The browser triggers connectedCallback under several
conditions: * When the HTML parser encounters the custom tag during
initial page load. * When you programmatically append the element using
methods like node.appendChild(),
node.append(), or
node.insertAdjacentElement(). * When an element is moved
from one parent node to another within the live document.
Because an element can be detached and re-attached multiple times,
connectedCallback can execute more than once during an
element’s lifetime.
Typical Use Cases
The connectedCallback method is the ideal place to
perform initialization tasks that require access to the DOM or parent
document context:
- Rendering DOM Content: Populating the element’s
innerHTMLor attaching nodes to its Shadow DOM. - Accessing Attributes and Children: Reading
attributes set in HTML or querying child nodes, which are not guaranteed
to be accessible inside the
constructor. - Setting Up Event Listeners: Attaching listeners to
the
window,document, or external services. - Fetching Remote Data: Initiating API calls or network requests needed to render the component.
- Registering Observers: Initializing
ResizeObserver,IntersectionObserver, orMutationObserverinstances.
Basic Implementation Example
Below is an example of a simple custom element utilizing
connectedCallback:
class UserBadge extends HTMLElement {
constructor() {
super();
// Initialize private state and attach shadow root
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
// Access attributes and render UI
const username = this.getAttribute('username') || 'Anonymous';
this.shadowRoot.innerHTML = `
<style>
.badge { font-family: sans-serif; padding: 4px 8px; background: #eee; border-radius: 4px; }
</style>
<span class="badge">User: ${username}</span>
`;
// Add global listener
this.handleResize = () => console.log('Window resized');
window.addEventListener('resize', this.handleResize);
}
disconnectedCallback() {
// Clean up to prevent memory leaks
window.removeEventListener('resize', this.handleResize);
}
}
customElements.define('user-badge', UserBadge);constructor vs. connectedCallback
Understanding the separation of responsibilities between the
constructor and connectedCallback is
critical:
| Feature | constructor() |
connectedCallback() |
|---|---|---|
| Execution | Runs once when instantiated | Runs every time the element is attached to the DOM |
| DOM Availability | Attributes and child nodes are unavailable | Full DOM context and attributes are available |
| Best Used For | Initializing state, creating Shadow Root | Fetching data, rendering UI, binding global events |
Important Considerations
- Always Pair with
disconnectedCallback: If you register global event listeners, timers, or observers inconnectedCallback, remove them indisconnectedCallbackto prevent memory leaks. - Guarding Multiple Executions: If you perform
expensive operations (like network requests) inside
connectedCallback, use a boolean flag (e.g.,this._hasInitialized) to ensure that re-attaching the element does not trigger duplicate initialization logic.