Cover image for The Fantastically Magical handleEvent Function

The Fantastically Magical handleEvent Function

rikschennink profile image Rik Schennink ・1 min read

Let's take a look!

I remember how I reacted when I found out about this years ago, also I still had a majestic mustache.

A man with a mustache saying: What the fuck?!?

That's right, this works, it's weird but it does.

If you set an object as the handler to addEventListener and said object has a property that is named handleEvent and that property is of type function the event is automatically sent there.

The reason this works (and works on all browsers):

The need for compatibility with legacy content required EventListener to accept both a function and an object with a handleEvent() property function.

EventListener on MDN

Another nice thing about this is that this keeps this working.

So, no need for bind(this) to ensure you end up in the right scope. Also, events are easily removed with removeEventListener('click', this)

Instead of having different functions to handle events, you can use a single handleEvent function to route all kinds of events.

class MyClass {

  constructor() {

    // Get a reference to the button node
    const btn = document.querySelector('button');
    const input = document.querySelector('input');

    // Handle clicks by this
    btn.addEventListener('click', this);

    // Handle input by this
    input.addEventListener('input', this);


  handleEvent(event) {
    if (event.type === 'click') {
      // handle button clicks 
    else if (event.type === 'input') {
      // handle text input


I hope this sparked some interesting new ideas for you to work with!

Posted on by:

rikschennink profile

Rik Schennink


Web enthusiast • FilePond.js • Conditioner.js • Doka.js • Runs PQINA, a tiny web plugin company


Editor guide

This post is great! If your event cases grow even farther than click and input, you can also implement dynamic dispatch to keep the complexity of handleEvent down:

const handler = {
  handleEvent(event) {
    return this[`${event.type}Event`] && // ensure that you don't throw if the function doesn't exist. 
                                  // Unless you prefer to surface those events, but you could also convert this to a ternary or `if-else` to log when a type you weren't expecting is sent through.

  clickEvent(event) { /* ... */ }

  inputEvent(event) { /* ... */ }

  submitEvent(event) { /* ... */ }

  dragEvent(event) { /* yaaas! */ }

  techTalkEvent(event) { /* oooh, **takes notes**... */ }


Oh yeah, and you can even assign different responsibilities to multiple handlers, then programmatically split up the behaviors of your UI, without ever having to worry about the memory or performance impacts of this.bind. AND!! The VM is smart enough not to assign the same handler to the same event more than once! handleEvent is LITERALLY the best.