0Pricing
HTML Academy · Lesson

Observed Attributes and attributeChangedCallback

React to HTML attribute changes in custom elements.

Observed Attributes and attributeChangedCallback is a free HTML Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Reacting to Attribute Changes

HTML elements expose state via attributes. To react when <my-card name="A"> becomes name="B", declare the observed attribute list and implement attributeChangedCallback on the class.

Static observedAttributes

Declare which attributes you care about via a static getter: static get observedAttributes() { return ["name", "open"]; }. Only attributes in this list trigger the callback — others are ignored for performance.

class MyCard extends HTMLElement {
  static get observedAttributes() { return ["name", "open"]; }
}

The Callback Signature

attributeChangedCallback(name, oldValue, newValue) fires for every observed attribute change. All three parameters are strings (or null if the attribute is absent). Use them to update internal state and re-render.

attributeChangedCallback(name, oldValue, newValue) {
  if (oldValue === newValue) return;
  if (name === "name") this.render();
  if (name === "open") this.toggle(newValue !== null);
}

Fires for Initial Attributes

The callback fires once for each observed attribute that is present when the element is upgraded. This means a render in attributeChangedCallback handles both initial and subsequent renders without a separate path in connectedCallback.

Property-Attribute Reflection

For boolean attributes, mirror the property to the attribute and vice versa: setting element.open = true should set the open attribute, and removing the attribute should clear the property. This matches how built-in elements like <details> behave.

get open() { return this.hasAttribute("open"); }
set open(value) {
  if (value) this.setAttribute("open", "");
  else this.removeAttribute("open");
}

Avoid Infinite Loops

If attributeChangedCallback sets attributes that it observes, you can spin into an infinite loop. Always guard with if (oldValue === newValue) return; at the top of the callback and avoid changing observed attributes from inside it.

Boolean Attributes

By HTML convention, boolean attributes are "set" by presence (disabled, open) and "unset" by absence. Their value is ignored — disabled="false" is still disabled. Check presence with hasAttribute, never compare the string.

JSON in Attributes

Attributes are strings. To pass structured data, JSON.stringify in markup and parse in attributeChangedCallback: <my-chart data-points='[1,2,3]'>. For large payloads, prefer passing data via JS property assignment instead.

Compared to MutationObserver

You could observe attribute changes with a MutationObserver, but observedAttributes + attributeChangedCallback is faster (no Observer setup), declarative (the list of observed names is visible on the class), and idiomatic for web components.

Performance: Coalesce Renders

Several attributes changing in rapid succession would trigger several callbacks and several renders. Coalesce with queueMicrotask or requestAnimationFrame so the actual render runs once per microtask/frame regardless of how many attributes changed.

Common Pitfall

Forgetting to add an attribute to observedAttributes silently disables the callback for that attribute. If your component does not react to a setAttribute call, the first thing to check is the static observedAttributes list.

Knowledge Check

What happens if you call attributeChangedCallback indirectly by setting an observed attribute inside the callback?

Summary

Declare which attributes to track via the static observedAttributes getter; attributeChangedCallback(name, oldValue, newValue) fires for each change including initial parse. Reflect properties to attributes for boolean state, guard against infinite loops, and coalesce renders with requestAnimationFrame for performance.

Frequently asked questions

Is the “Observed Attributes and attributeChangedCallback” lesson free?

Yes — the full text of “Observed Attributes and attributeChangedCallback” is free to read here on the web, and the HTML Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the HTML Academy course, upgrade to CoddyKit PRO.

What will I learn in “Observed Attributes and attributeChangedCallback”?

React to HTML attribute changes in custom elements. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start HTML Academy?

No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Observed Attributes and attributeChangedCallback” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this HTML Academy lesson?

Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Defining Elements with customElements.define
  2. The connectedCallback and disconnectedCallback
  3. Observed Attributes and attributeChangedCallback
  4. Extending Built-in Elements
← Back to HTML Academy