connectedCallback
This lesson explains connectedCallback with clear examples, use cases, and best practices so you can build reusable Web Components confidently.
What Is connectedCallback?
connectedCallback() is a Web Component lifecycle method that
runs every time a custom element is added to the document.
It is commonly used to render markup, attach event listeners, read
attributes, start timers, fetch data, or initialize component behavior.
| Concept | Description |
connectedCallback() | Runs when the element is inserted into the DOM |
| Lifecycle Type | Custom Element lifecycle callback |
| Common Use | Render UI, add events, initialize state, fetch data |
| Runs Multiple Times? | Yes, if the element is removed and added again |
| Paired With | disconnectedCallback() for cleanup |
| Main Benefit | Safely initializes component logic after DOM connection |
Basic connectedCallback Example
class HelloMessage extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<p>Hello from Web Component!</p>
`;
}
}
customElements.define("hello-message", HelloMessage);
<hello-message></hello-message>
When <hello-message> is added to the page,
connectedCallback() runs and renders the paragraph.
How connectedCallback Works
| Step | What Happens |
| 1. Custom element is defined | customElements.define() registers the component |
| 2. Element appears in DOM | The browser finds the custom element on the page |
| 3. Browser upgrades element | The class logic is connected to the HTML element |
| 4. Element connects | connectedCallback() is called |
| 5. Component initializes | Markup, events, state, or data logic can run |
Constructor vs connectedCallback
| Feature | constructor() | connectedCallback() |
| Runs When | Element instance is created | Element is added to the DOM |
| Best For | Initial setup, Shadow DOM creation | Rendering, events, DOM-based logic |
| Can Read Attributes? | Not always recommended | Yes, commonly used |
| Can Access Children? | Not safely | Yes, usually safer |
connectedCallback With Shadow DOM
class AppButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
button {
padding: 0.5rem 1rem;
border-radius: 0.5rem;
border: 1px solid #0d6efd;
background: #0d6efd;
color: white;
}
</style>
<button type="button">
<slot>Click Me</slot>
</button>
`;
}
}
customElements.define("app-button", AppButton);
<app-button>Save</app-button>
The constructor creates the Shadow DOM. The
connectedCallback() method renders the component UI after the
element is connected to the page.
Reading Attributes in connectedCallback
class UserBadge extends HTMLElement {
connectedCallback() {
const name = this.getAttribute("name") || "Guest";
const role = this.getAttribute("role") || "User";
this.innerHTML = `
<div class="badge">
<strong>${name}</strong>
<span>${role}</span>
</div>
`;
}
}
customElements.define("user-badge", UserBadge);
<user-badge name="Ayaan" role="Student"></user-badge>
Attributes are often read inside connectedCallback() because
the element is already available in the document.
Adding Event Listeners in connectedCallback
class CounterButton extends HTMLElement {
constructor() {
super();
this.count = 0;
}
connectedCallback() {
this.innerHTML = `
<button type="button">Clicked 0 times</button>
`;
this.querySelector("button").addEventListener("click", () => {
this.count++;
this.querySelector("button").textContent =
`Clicked ${this.count} times`;
});
}
}
customElements.define("counter-button", CounterButton);
<counter-button></counter-button>
connectedCallback() is a common place to attach event
listeners because the component markup has already been rendered.
Cleanup With disconnectedCallback
class WindowSizeTracker extends HTMLElement {
connectedCallback() {
this.handleResize = () => {
this.textContent = `Width: ${window.innerWidth}`;
};
window.addEventListener("resize", this.handleResize);
this.handleResize();
}
disconnectedCallback() {
window.removeEventListener("resize", this.handleResize);
}
}
customElements.define("window-size-tracker", WindowSizeTracker);
If connectedCallback() adds global event listeners, timers, or
subscriptions, clean them up inside disconnectedCallback().
connectedCallback Can Run Multiple Times
class SimplePanel extends HTMLElement {
connectedCallback() {
console.log("Panel connected");
}
}
customElements.define("simple-panel", SimplePanel);
const panel = document.createElement("simple-panel");
document.body.appendChild(panel);
panel.remove();
document.body.appendChild(panel);
In this example, connectedCallback() runs each time the same
element is added back to the document.
Avoid Duplicate Initialization
class SafeCard extends HTMLElement {
connectedCallback() {
if (this.hasInitialized) {
return;
}
this.hasInitialized = true;
this.innerHTML = `
<article>
<h2>Profile Card</h2>
<p>This card renders only once.</p>
</article>
`;
}
}
customElements.define("safe-card", SafeCard);
Use a flag when your component should initialize only once, especially if
it may be moved around in the DOM.
Fetching Data in connectedCallback
class ProductInfo extends HTMLElement {
async connectedCallback() {
this.innerHTML = `<p>Loading product...</p>`;
const productId = this.getAttribute("product-id");
const response = await fetch(`/api/products/${productId}`);
const product = await response.json();
this.innerHTML = `
<article>
<h2>${product.name}</h2>
<p>${product.description}</p>
</article>
`;
}
}
customElements.define("product-info", ProductInfo);
You can fetch data inside connectedCallback(), but handle
loading states and errors properly in production components.
When to Use connectedCallback
- Render initial HTML for a custom element.
- Read attributes after the element is connected.
- Attach event listeners to internal elements.
- Start timers, observers, or subscriptions.
- Fetch data needed for the component UI.
- Initialize logic that depends on the document.
Common connectedCallback Use Cases
- Rendering cards, buttons, modals, tabs, and menus.
- Initializing Shadow DOM content.
- Adding click, input, submit, or keyboard events.
- Reading attributes like
type, label, and value. - Starting API calls when the component appears.
- Connecting to observers such as
ResizeObserver or IntersectionObserver.
connectedCallback Best Practices
- Use the constructor for basic setup and Shadow DOM creation.
- Use
connectedCallback() for DOM-related initialization. - Remember that
connectedCallback() can run more than once. - Clean up listeners, timers, and observers in
disconnectedCallback(). - Avoid rendering duplicate markup on repeated connections.
- Keep heavy logic separate in helper methods.
- Handle loading and error states when fetching data.
Common connectedCallback Mistakes
- Assuming
connectedCallback() runs only once. - Adding duplicate event listeners every time the element reconnects.
- Not cleaning up global event listeners.
- Doing too much work directly inside the lifecycle method.
- Using
innerHTML repeatedly and losing event listeners. - Trying to access child content too early in the constructor.
- Forgetting to handle missing attributes or API errors.
Key Takeaways
connectedCallback() runs when a custom element enters the DOM. - It is ideal for rendering, events, attribute reading, and setup logic.
- It can run multiple times during the element lifecycle.
- Use
disconnectedCallback() to clean up side effects. - Good lifecycle management makes Web Components reliable and reusable.
Pro Tip
Treat connectedCallback() as the place where your component
becomes active. Render the UI, attach events, and start external work
there, but always clean up long-running side effects in
disconnectedCallback().