Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

One AbortController Can Tear Down All Your Event Listeners

C
Carlo Fontanos
· 2 min read

Everybody knows the removeEventListener trap: it only works if you pass the exact same function reference you added. So you end up storing bound handlers on the instance, or keeping a little registry of functions purely so you can unhook them later. I did this for years.

Then I found out addEventListener accepts an AbortSignal, the same one fetch() uses:

const controller = new AbortController();

window.addEventListener('resize', onResize, { signal: controller.signal });
window.addEventListener('scroll', onScroll, { signal: controller.signal });
document.addEventListener('keydown', onKey, { signal: controller.signal });
button.addEventListener('click', onClick, { signal: controller.signal });

// Later - all four gone in one call:
controller.abort();

No references to keep, no mismatch bugs, and it even works with anonymous arrow functions, which removeEventListener never could.

Where this shines: components and SPAs

Any widget that attaches listeners outside its own root (window, document, a parent container) needs teardown, or it leaks. The controller pattern turns that into two lines:

class Dropdown {
    #controller = new AbortController();

    constructor(root) {
        const { signal } = this.#controller;
        root.addEventListener('click', e => this.toggle(e), { signal });
        document.addEventListener('click', e => this.closeIfOutside(e), { signal });
        document.addEventListener('keydown', e => this.onEscape(e), { signal });
    }

    destroy() {
        this.#controller.abort();
    }
}

The destroy() method doesn't need to know what was registered. New listeners added later automatically join the same teardown group as long as they use the same signal.

Bonus: one signal for listeners and fetches together

Because it's the same AbortController API, a single controller can cancel in-flight requests and remove listeners at the same time. For an autocomplete field that fires requests while typing, aborting on teardown cleans up both the network and the DOM side in one shot.

Support is excellent - Chrome 90+, Firefox 86+, Safari 15+. If you're still writing removeEventListener by hand, this is the upgrade. It pairs nicely with the other addEventListener options most people skip past.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading