A lot of things happen on webpages. People scroll, click, and move their mouses. Form inputs get entered and typed into. Pages load or get resized. These actions (and many others) are aptly called ‘events’ in web development. And responding to these events is a large part of what makes web applications interactive. Users do things on a page and the page responds in turn. JavaScript is what we use to handle events and give an appropriate response to them.

This post will give a background and overview (with code examples) of how we can handle events with JavaScript. We’ll stay at a relatively high-level so you can quickly learn the gist of events without getting bogged down in minutiae.

Types of Events

Before covering the 3 primary ways of handling JavaScript events, it’s worth knowing what types of events there are. MDN has the one of the easiest to read resources on this. If you go there, you’ll see there’s a ton of different event types! WebMonkey has a nice categorization of them:

Page Events

Form Events

Keyboard Events

Mouse Events

I think those are mostly self-explanatory and can help you chunk the events better. You don’t need to know every event in the spec by heart. The big takeaway here is that we can track and respond to just about everything a user might do on a webpage. So what are the primary ways that we can do this? Read on.

Method #1: Event Handlers

Event handlers are the first way that developers respond(ed) to events. Event handlers are also called inline event handlers. That’s because they are put right into the html elements. You’ve probably seen them in the form on onclick or onload.

As you can see here, the onClick handler is put right onto the the anchor element. It will alert ‘welcome’ if it is clicked. Seems pretty straightforward, so what are the disadvantages of this approach?

Disadvantages:

Mixing markup with functionality

This breaks the separation of concerns tenet in programming. You generally want to keep JavaScript separate from HTML and not mix the two. This also applies to inline styling with CSS (inline styling is generally bad).

You can only put one handler per element

If you need to respond to other types of events on that element, too bad.

HTML file size

Putting event handlers in your HTML is going to make your pages a lot heavier.

Difficult code maintenance

If you need to make changes to your event handlers you’re going to have to do so on every single element vs. changing things once in a Javascript file.

Polluting Global Scope

This is a big No-No in JavaScript. You do not want to put unnecessary methods onto the global object because this could cause collisions if someone else uses the same method name for their code.

So event handlers were what came first and they work but there’s many drawbacks. Event listeners offer us a much better way to do this.

Method #2: Event Listeners (Observer pattern)

This event pattern relies on something called the “observer model”. The observer is the browser. The developer registers event listeners with the browser and says “hey browser, listen up. If this particular action happens, do this (aka run this function)”.

An Element, a Method, an Event, a Function…

The syntax for registering an event listener is pretty simple. Check out this jsfiddle that shows you which event is currently occurring on a page. Here’s an example from that fiddle.

Another way to understand this is imagine the developer is saying “Hey Browser, listen for when someone mouses over the document (the entire page). When they do that, call the sendOutput function. Note: you can register event listeners on any DOM nodes, not just HTML elements.

So event listeners are clearly an improvement over events handlers. So what are the downsides of using them?

Performance

Event listeners are not free. Your page/app will slow down when you have to attach Event Listeners to several hundred or thousand nodes.

Tedium

It takes a lot of extra work and maintenance to register and track so many event listeners in an HTML document. What if you have list items or particular DOM nodes that are coming and going and changing a lot? With event listeners, you’re going to have to be constantly attaching and removing listeners as the DOM changes.

Event listeners give us a much better syntax but they are also not without their drawbacks.

A note about Bubbling and Capturing

You now need to know a bit about the phases of events. This can be a bit of a rabbit hole so we’ll try to keep this simple and high-level.

An event does not just occur on the element itself. It also occurs on all of its ancestors (parents and grandparents and so on). Let me show you with a code demo or we’ll get lost here otherwise.

What’s happening there? The term is event propagation, which includes capturing and bubbling. Capturing starts at the highest level of the DOM and fires/propagates the event on every ancestor until it hits the exact element where the event occurs. It then does the reverse in a process called bubbling.

Capturing makes a sound like this:

Bubbling, however, sounds like this:

Capturing/Bubbling are a rabbit hole like I said. They have to do with Netscape vs. Microsoft in the 90s and compromises and the chaotic evolution of the technologies that make up our beloved Internet. But we don’t need to go there.

Instead, let’s just focus on bubbling. Bubbling is where an event on a child (e.g. <li>) will propagate up to it’s parents, their parents, and their parents, all the way to the root of the document. Bubbling is what allows us to do event delegation.

Method #3 – Event Delegation

We know events are going to bubble up the DOM. So imagine we have some HTML like this:

<html> <body> <ul> <li id="li_1"><button id="button_1">Button A</button></li> <li id="li_2"><button id="button_2">Button B</button></li> <li id="li_3"><button id="button_3">Button C</button></li> </ul> </body> </html>

Now imagine that someone clicks on one of those buttons. If we were to use Method #2 (Event Listeners), we’d have to register a separate event listener onto each of those buttons (bleck).

But we know the event will bubble up from the <li> to the <ul> parent. What if we register an event listener on the <ul> and have it figure out which of its children got clicked? This is event delegation in a nutshell. The key is listen on the parents, not the children. Here’s the syntax.

Here’s the code in action. I’m going to use jQuery and explain why later.

jQuery excels at simplifying event delegation. You can, of course, do it in vanilla js but it takes roughly 4-5x as many lines.

In that particular example, I’m logging the event.target.nodeName. But try logging the event.target or just the event to get a sense for what other types of properties the event objects contain.

Here’s another really cool demo I found on CodePen where you can learn more about Bubbling through play:

See the Pen Bubbler – an event bubbling demonstration by Adam McFadden (@adammcfadden) on CodePen.



Summary

This article covered, at a high level, how events can be handled using JavaScript. There’s a lot more to the story then we could cover in 1300 words so below I’m going to put some recommended reading if you’d like to dig in more. That said this should give you enough of a conceptual framework for how events have evolved and how developers use JavaScript to respond to them.

Recommended Reading

Event Delegation – David Walsh Blog

Monitor all JavaScript events in the browser console

Emerging Patterns in JavaScript Event Handling