disconnectedCallback and Cleanup
When disconnectedCallback fires
Section titled “When disconnectedCallback fires”disconnectedCallback is called each time the element is removed from a connected document. Common cleanup tasks belong here:
- Remove event listeners added in
connectedCallback - Cancel
setIntervalorsetTimeouttimers - Close WebSocket connections
- Disconnect
MutationObserver,ResizeObserver, orIntersectionObserverinstances
One important caveat: disconnectedCallback is not called when the entire page is unloaded (e.g. the user navigates away or closes the tab). It is only triggered by explicit DOM removal such as removeChild, replaceWith, or innerHTML reassignment.
The symmetry pattern
Section titled “The symmetry pattern”Think of connectedCallback and disconnectedCallback as matching brackets. Whatever resource you acquire when the element enters the DOM, you release when it leaves:
class TimerDemo extends HTMLElement { connectedCallback() { // start work this._intervalId = setInterval(this._tick.bind(this), 1000); }
disconnectedCallback() { // stop work — mirror of connectedCallback clearInterval(this._intervalId); }
_tick() { // called every second while connected }}Storing the handle (this._intervalId) on the element instance is the standard way to make it accessible to disconnectedCallback.
Full timer pattern
Section titled “Full timer pattern”class TimerDemo extends HTMLElement { connectedCallback() { this._seconds = 0; this._render(); this._intervalId = setInterval(this._tick.bind(this), 1000); }
disconnectedCallback() { clearInterval(this._intervalId); }
_tick() { this._seconds += 1; this._render(); }
_render() { this.textContent = 'Running: ' + this._seconds + 's'; }}
customElements.define('timer-demo', TimerDemo);Live demo
Section titled “Live demo”Click Remove timer to remove the element from the DOM — the log line confirms disconnectedCallback fired and the timer stopped. Click Re-add timer to re-insert a fresh element; the counter resets and the log shows connectedCallback running again.