Skip to main content Accessibility Feedback

A vanilla JavaScript equivalent of jQuery’s on() method

In vanilla JavaScript, you can listen to browser events with the addEventListener() method.

var link = document.querySelector('#some-link');
link.addEventListener('click', function (event) {

    // Prevent the link from updating the URL
    event.preventDefault();

    // Do something...

}, false);

If you’re used to the jQuery way, it can feel pretty verbose. Today, I want to share a vanilla JavaScript version of the on() method.

The on() method

First, I’ll show you how to use it. Then, I’ll share the method itself. And finally, I’ll break down how it works.

How to use it

The first argument is always the event to listen to. The second argument is an optional filter, if you only want to listen to events on a certain selector.

You can omit it and jump straight to argument three, the callback. This is the function to run on the event. There’s a final, optional argument: use capture. Set it to true for non-bubbling events (like focus) that you need to force to bubble.

// Listen to all click events
on('click', function(event) {
    // The thing that was clicked
    var clicked = event.target;
});

// Listen to all clicks on links with the .click-me class
on('click', '.click-me', function(event) {
    // Prevent the link from working
    event.preventDefault();
});

// Listen to focus on any element in the document with `use capture`
on('focus', function (event) {
    // The element that came into focus
    var focused = event.target;
}, true);

You can also pass in named functions if you need to be able to remove the event listener later (more on that tomorrow) or want to use the same function for multiple events.

// Do stuff on scroll
var onScrollHandler = function (event) {
    // Do something on scroll...
};

// Setup the event listener
on('scroll', onScrollHandler);

The helper method

/*!
 * Add an event listener
 * (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param  {String}   event    The event type
 * @param  {Node}     elem     The element to attach the event to (optional, defaults to window)
 * @param  {Function} callback The callback to run on the event
 * @param  {Boolean}  capture  If true, forces bubbling on non-bubbling events
 */
var on = function (event, elem, callback, capture) {
	if (typeof (elem) === 'function') {
		capture = callback;
		callback = elem;
		elem = window;
	}
	capture = capture ? true : false;
	elem = typeof elem === 'string' ? document.querySelector(elem) : elem;
	if (!elem) return;
	elem.addEventListener(event, callback, capture);
};

How it works

First, we check to see if the second argument is an element selector or a callback function. If it’s our callback, we’ll shift all of the arguments over one.

if (typeof (elem) === 'function') {
	capture = callback;
	callback = elem;
	elem = window;
}

Next, we check to see if the capture argument is set. If not, we’ll use false instead of null.

capture = capture ? true : false;

Then, we look to see if our elem is a string or a node. If it’s a string, we’ll use querySelector() to find the actual element to listen on. If it doesn’t exist, we’ll bail before adding an event listener.

elem = typeof elem === 'string' ? document.querySelector(elem) : elem;
if (!elem) return;

Finally, we’ll add our event listener.

elem.addEventListener(event, callback, capture);