How to Resolve the "Unable to preventDefault inside passive event listener" Error in JavaScript
The error message [Intervention] Unable to preventDefault inside passive event listener... is a common warning in modern browsers like Chrome. It occurs when you call event.preventDefault() inside a touch event listener (like touchstart or touchmove) that the browser has marked as "passive." This is a feature, not a bug, designed to improve scrolling performance.
This guide will explain what passive event listeners are, why this error happens, and show you the two correct ways to solve it: by explicitly marking your listener as active in JavaScript, or by using the CSS touch-action property.
The Core Problem: Passive Event Listeners and Scrolling Performance
To improve user experience, browsers want to start scrolling the page as soon as a user touches and drags their finger. However, a JavaScript touchmove event listener has the ability to call event.preventDefault(), which would cancel the scroll.
- The Dilemma: The browser doesn't know if your listener will cancel the scroll until after your JavaScript code has finished running. This can force the browser to wait, causing a noticeable delay or "jank" before scrolling starts.
- The Solution (Passive Listeners): To fix this, modern browsers made a change. By default, they now treat
touchstartandtouchmoveevent listeners as passive. A passive listener is a "promise" to the browser that you will not callevent.preventDefault(). Because of this promise, the browser can start scrolling immediately without waiting for your listener to finish, resulting in a much smoother experience.
The error message is the browser telling you, "You promised you wouldn't call preventDefault() in this listener, but you did anyway, so I'm ignoring it."
The JavaScript Solution (Recommended): Set passive: false
If you do need to call event.preventDefault() to block scrolling or other touch behaviors, you must explicitly tell the browser that your listener is not passive. You do this by passing an options object as the third argument to addEventListener().
Example of problem:
// This will cause the error because the listener is passive by default.
document.addEventListener('touchmove', (event) => {
// The browser will ignore this call.
event.preventDefault();
});
Solution: set the passive property to false in the options object.
document.addEventListener(
'touchmove',
(event) => {
// This will now work correctly and prevent scrolling.
event.preventDefault();
},
{ passive: false } // Explicitly mark the listener as active.
);
This is the correct and definitive JavaScript solution for enabling preventDefault() in touch event listeners.
The CSS Solution (Often Better): The touch-action Property
In many cases, you can achieve your goal without any JavaScript at all by using the CSS touch-action property. This property provides a declarative way to tell the browser exactly which touch gestures (like panning and zooming) are allowed on an element.
Problem: you have a canvas or a map div where you want to handle touch events for drawing or custom panning, and you want to prevent the browser's default scrolling behavior within that element.
Solution: apply the touch-action property to the element in your CSS.
#my-canvas {
/* Disables all default browser gestures like panning and zooming on this element. */
touch-action: none;
}
When touch-action is set to none, the browser will not perform any default touch actions on that element, and you will no longer need to call event.preventDefault() in your JavaScript, thus avoiding the error entirely. This is often the cleanest and most performant solution.
Solutions to Avoid
You may see other suggested "fixes" online that do not actually solve the problem.
if (event.cancelable): A passive event listener will have itscancelableproperty set tofalse. So, wrappingpreventDefault()inif (event.cancelable)will prevent the error message, but it will also prevent your code from ever running. It just makes the failure silent.- Removing
event.preventDefault(): This is only a solution if you didn't actually need to prevent the default action in the first place. If you need to stop scrolling, removing this line is not a solution.
Conclusion
The "Unable to preventDefault inside passive event listener" error is a performance-related feature of modern browsers.
To solve it, you have two excellent options:
- The JavaScript Solution: If you must call
event.preventDefault(), explicitly mark your event listener as active by passing{ passive: false }as the third argument toaddEventListener(). - The CSS Solution: If your goal is simply to prevent default touch behaviors like scrolling on a specific element, the recommended best practice is to use the CSS
touch-actionproperty (e.g.,touch-action: none;).