Skip to content

Rendering Content

Why connectedCallback, not the constructor

Section titled “Why connectedCallback, not the constructor”

A custom element class has a constructor like any other ES class, but the constructor is the wrong place to do DOM work. When the browser calls the constructor, the element exists as a JavaScript object but it has not yet been added to the document — it has no parent, its attributes may not be fully parsed, and its children are not yet present.

Use connectedCallback instead. It fires each time the element is inserted into a connected document, at which point the element’s attributes and light DOM children are available:

class MyCard extends HTMLElement {
constructor() {
super(); // always required
// DO NOT touch this.innerHTML, this.children, or attributes here
}
connectedCallback() {
// Safe to read attributes and manipulate DOM here
const title = this.getAttribute('title') || 'Card';
this.innerHTML = '<h2>' + title + '</h2>';
}
}

innerHTML is the quickest way to stamp out a template:

connectedCallback() {
this.innerHTML = '<p>Hello from <strong>innerHTML</strong></p>';
}

For dynamic or user-supplied values, always sanitize first or use DOM APIs instead to avoid XSS:

connectedCallback() {
const p = document.createElement('p');
const userInput = this.getAttribute('label') || '';
p.textContent = userInput; // textContent never parses HTML
this.appendChild(p);
}

this.getAttribute(name) returns the attribute value as a string, or null if the attribute is absent. The pattern this.getAttribute('x') || 'default' is safe because null || 'default' evaluates to 'default':

connectedCallback() {
const color = this.getAttribute('color') || 'blue';
const label = this.getAttribute('label') || 'Button';
this.innerHTML =
'<button style="background:' + color + '">' + label + '</button>';
}

Try adding a second <color-card> tag with a different color and label in the HTML panel.

Why should you avoid setting innerHTML in the constructor?
What does connectedCallback fire?
Which approach is safer when rendering user-supplied data?
What does getAttribute return when an attribute is not present on the element?