Skip to main content Accessibility Feedback

Removing an event listener with vanilla JavaScript

Yesterday, we looked at a vanilla JavaScript equivalent of jQuery’s on() method. Today, let’s look at the vanilla JS version of off(), which removes an event listener.

The completely native way

With vanilla JavaScript, you can remove any named event listener with removeEventListener(). It accepts all of the same arguments as addEventListener(), and those arguments must match the ones you used to add the event.

So, for example, if you added this click event:

var clickHandler = function (event) {

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

    // Do something...

};

var link = document.querySelector('#some-link');
link.addEventListener('click', clickHandler, false);

You can remove it like this:

link.removeEventListener('click', clickHandler, false);

The off() 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 off() method works just like the on() method we discussed yesterday.

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

You can omit it and jump straight to argument three, the callback. This is the function that runs on the event, and for this to work, it must be named. The final optional argument is use capture.

All of the arguments must match the ones you used in on(). So, if you did this:

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

You’d remove it like this:

off('click', '.click-me', clickHandler);

If you used event bubbling like this:

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

You’d remove it like this:

off('click', allClicks);

The Helper Method

/*!
 * Remove an event listener
 * (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param  {String}   event    The event type
 * @param  {Node}     elem     The element to remove the event to (optional, defaults to window)
 * @param  {Function} callback The callback that ran on the event
 * @param  {Boolean}  capture  If true, forces bubbling on non-bubbling events
 */
var off = 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.removeEventListener(event, callback, capture);
};

How it works

We’re essentially doing the same thing we did in our on() method, and then calling removeEventListener() instead.

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 the listener is attached to. If it doesn’t exist, we’ll bail before removing an event listener.

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

Finally, we remove our event listener.

elem.removeEventListener(event, callback, capture);