EventTarget.removeEventListener()

The EventTarget.removeEventListener() method removes from the EventTarget an event listener previously registered with EventTarget.addEventListener(). The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal

Syntax

target.removeEventListener(type, listener[, options]);
target.removeEventListener(type, listener[, useCapture]);

Parameters

type
A string which specifies the type of event for which to remove an event.
listener
The EventListener function of the event handler to remove from the event target.
options Optional
An options object that specifies characteristics about the event listener. The available options are:
  • capture: A Boolean that indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.  
  • passive: A Boolean indicating that the listener will never call preventDefault(). If it does, the user agent should ignore it and generate a console warning.
  • mozSystemGroup: Available only in code running in XBL or in Firefox' chrome, it is a Boolean defining if the listener is added to the system group.
useCapture Optional
Specifies whether the EventListener to be removed is registered as a capturing listener or not. If this parameter is absent, a default value of false is assumed.
If a listener is registered twice, one with capture and one without, remove each one separately. Removal of a capturing listener does not affect a non-capturing version of the same listener, and vice versa.

Return value

undefined.

Matching event listeners for removal

Given an event listener previously added by calling addEventListener(), you may eventually come to a point at which you need to remove it. Obviously, you need to specify the same type and listener parameters to removeEventListener(), but what about the options or useCapture parameters?

While addEventListener() will let you add the same listener more than once for the same type if the options are different, the only option removeEventListener() checks is the capture/useCapture flag. Its value must match for removeEventListener() to match, but the other values don't.

For example, consider this call to addEventListener():

element.addEventListener("mousedown", handleMouseDown, true);

Now consider each of these two calls to removeEventListener():

element.removeEventListener("mousedown", handleMouseDown, false);     // Fails
element.removeEventListener("mousedown", handleMouseDown, true);      // Succeeds

The first call fails because the value of useCapture doesn't match. The second succeeds, since useCapture matches up.

Now consider this:

element.addEventListener("mousedown", handleMouseDown, { passive: true });

Here, we specify an options object in which passive is set to true, while the other options are left to the default value of false.

Now look at each of these calls to removeEventListener() in turn. Any of them in which capture or useCapture is true fail; all others succeed. Only the capture setting matters to removeEventListener().

element.removeEventListener("mousedown", handleMouseDown, { passive: true });     // Succeeds
element.removeEventListener("mousedown", handleMouseDown, { capture: false });    // Succeeds
element.removeEventListener("mousedown", handleMouseDown, { capture: true });     // Fails
element.removeEventListener("mousedown", handleMouseDown, { passive: false });    // Succeeds
element.removeEventListener("mousedown", handleMouseDown, false);                 // Succeeds
element.removeEventListener("mousedown", handleMouseDown, true);                  // Fails

It's worth noting that some browser releases have been inconsistent on this, and unless you have specific reasons otherwise, it's probably wise to use the same values used for the call to addEventListener() when calling removeEventListener().

Notes

If an EventListener is removed from an EventTarget while it is processing an event, it will not be triggered by the current actions. An EventListener will not be invoked for the event it was registered for after being removed. However, it can be reattached.

Calling removeEventListener() with arguments that do not identify any currently registered EventListener on the EventTarget has no effect.

Example

This example shows how to add a click-based event listener and remove a mouseover-based event listener.

var body =
        document.querySelector('body'),
    clickTarget =
        document.getElementById('click-target'),
    mouseOverTarget =
        document.getElementById('mouse-over-target'),
    toggle = false;
function makeBackgroundYellow() {
    'use strict';
    if (toggle) {
        body.style.backgroundColor = 'white';
    } else {
        body.style.backgroundColor = 'yellow';
    }
    toggle = !toggle;
}
clickTarget.addEventListener('click',
    makeBackgroundYellow,
    false
);
mouseOverTarget.addEventListener('mouseover', function () {
    'use strict';
    clickTarget.removeEventListener('click',
        makeBackgroundYellow,
        false
    );
});

Specifications

Specification Status Comment
DOM
The definition of 'EventTarget.removeEventListener()' in that specification.
Living Standard  
DOM4
The definition of 'EventTarget.removeEventListener()' in that specification.
Recommendation  
Document Object Model (DOM) Level 2 Events Specification
The definition of 'EventTarget.removeEventListener()' in that specification.
Recommendation Initial definition

Browser compatibility

Feature Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support 1.0[1][2] (Yes) 1.0 (1.7 or earlier)[3] 9.0 7[4] 1.0[1]
useCapture made optional (Yes) (Yes) 6.0 9.0 11.60 (Yes)
options parameter 49.0 No support        
Feature Android Android Webview Edge Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support 1.0[1] (Yes)[2] (Yes) 1.0 (1)[3] 9.0 6.0[4] 1.0[1] (Yes)[2]
useCapture made optional ? (Yes) (Yes)         (Yes)
options parameter No support 49.0 No support         49.0

[1] Although WebKit explicitly added "[optional]" to the useCapture parameter for Safari 5.1 and Chrome 13, it had been working before the change.

[2] Before Chrome 49, the type and listener parameters were optional.

[2] Before Firefox 6, the browser would throw an exception if the useCapture parameter was not explicitly false. Before Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6), addEventListener() would throw an exception if the listener parameter was null; now the method returns without error, but without doing anything.

[4] Opera 11.60 made the useCapture parameter optional (source).

[5] For backward compatibility, browsers that support options allow the third parameter to be either options or Boolean.

Polyfill to support older browsers

addEventListener() and removeEventListener() are not present in older browsers. You can work around this by inserting the following code at the beginning of your scripts, allowing the use of addEventListener() and removeEventListener() in implementations that do not natively support it. However, this method will not work on Internet Explorer 7 or earlier, since extending the Element.prototype was not supported until Internet Explorer 8.

if (!Element.prototype.addEventListener) {
  var oListeners = {};
  function runListeners(oEvent) {
    if (!oEvent) { oEvent = window.event; }
    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
      if (oEvtListeners.aEls[iElId] === this) {
        for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
        break;
      }
    }
  }
  Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
    if (oListeners.hasOwnProperty(sEventType)) {
      var oEvtListeners = oListeners[sEventType];
      for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
        if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
      }
      if (nElIdx === -1) {
        oEvtListeners.aEls.push(this);
        oEvtListeners.aEvts.push([fListener]);
        this["on" + sEventType] = runListeners;
      } else {
        var aElListeners = oEvtListeners.aEvts[nElIdx];
        if (this["on" + sEventType] !== runListeners) {
          aElListeners.splice(0);
          this["on" + sEventType] = runListeners;
        }
        for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
          if (aElListeners[iLstId] === fListener) { return; }
        }     
        aElListeners.push(fListener);
      }
    } else {
      oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };
      this["on" + sEventType] = runListeners;
    }
  };
  Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
    if (!oListeners.hasOwnProperty(sEventType)) { return; }
    var oEvtListeners = oListeners[sEventType];
    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
      if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
    }
    if (nElIdx === -1) { return; }
    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
      if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
    }
  };
}

See also