Passive Event Listeners
Passive listeners promise the browser that touch and wheel handlers will never call preventDefault, letting scrolling start immediately instead of waiting for JavaScript to finish.
Definition
A passive event listener is registered with the passive option, telling the browser the handler cannot cancel the event. For touch and wheel events the browser can then begin scrolling without waiting for the handler to run to completion, removing scroll jank caused by main-thread-bound handlers. Default listener behavior for these events is passive in modern browsers.
Context and scope
Scroll-linked analytics, scroll-triggered effects, and any touch or wheel handler that observes but never intercepts. Non-passive is needed only when actually calling preventDefault.
Common misconceptions
- Passive listeners make handlers faster — they decouple scroll start from handler duration; the handler itself runs the same
- Calling preventDefault in a passive listener throws silently — it is ignored with a console warning, not an exception
- Only touch events benefit — wheel and touchmove dominate, and browser defaults already make many of these passive
Anti-patterns
- Registering non-passive touchmove handlers just to observe scroll positions, opting out of browser defaults for no reason
- Doing heavy work in scroll handlers and assuming passive registration removes the jank it causes
- Needing preventDefault for a pull-to-refresh gesture and leaving the listener passive, shipping a broken gesture
Related concepts
Related examples
Authoritative source
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
What it is
The browser cannot know in advance whether a scroll handler will cancel the scroll, so historically it waited for the handler before scrolling. A passive promise says cancellation will not happen, so scrolling proceeds while JavaScript runs. Scrolling stays compositor-driven even when the main thread is busy.
How it works
addEventListener with passive: true registers the promise. preventDefault inside such a handler is ignored, and the browser logs a warning. Root touch and wheel listeners on window or document default to passive in Chrome and Safari, so opting out is now the explicit choice that costs smoothness.
When to use it
Every observer-style scroll or touch handler: analytics, parallax triggers, infinite scroll detection. Reserve non-passive for genuine interceptors: custom gestures, pull-to-refresh, horizontal carousels that must swallow vertical scrolls.
Pitfalls
Passivity does not excuse slow handlers: long scroll handlers still delay other main-thread work such as layout or pending timers. Gesture code that silently fails to preventDefault produces half-broken interactions. Feature-test defaults, since older engines treat all listeners as non-passive.