The wheel event fires when the user rotates a mouse wheel or a related device (trackpad, mouse ball). Learn addEventListener vs onwheel, WheelEvent deltas, passive listeners, how it differs from scroll, custom zoom with preventDefault, and five try-it labs.
01
Kind
Instance event
02
Type
WheelEvent
03
When
Wheel / trackpad rotate
04
Handler
onwheel
05
Bubbles?
Yes
06
Status
Limited availability
Fundamentals
Introduction
wheel answers: “Did the user turn a wheel or trackpad?” That is an input intent signal—not a guarantee that content scrolled. It is also the modern replacement for the obsolete mousewheel event.
Zooming with Ctrl + wheel / trackpad pinch often fires wheel with ctrlKey set to true. Canceling the event can block scrolling or zooming, but blocking every wheel can hurt scroll performance—prefer { passive: true } when you only listen.
💡
Beginner tip
Need to know if the page actually moved? Listen for scroll and read scrollTop / scrollLeft. Do not trust deltaY alone as the scroll direction.
Concept
Understanding wheel
An instance event that answers: “Did a pointing device report a wheel-like rotation over this element?”
Trigger — mouse wheel, trackpad scroll gesture, or similar.
Event type — WheelEvent with deltaX, deltaY, deltaZ, deltaMode.
Bubbles — yes; can be listened for on ancestors.
Cancelable — yes (sometimes only the first event in a sequence).
Limited availability on MDN (not Baseline)—notably missing on Safari iOS.
Foundation
📝 Syntax
Use the event name with addEventListener, or set the handler property:
A WheelEvent (inherits from MouseEvent, UIEvent, and Event).
Handy WheelEvent properties
Property
Meaning
deltaX
Horizontal scroll amount (read-only double)
deltaY
Vertical scroll amount (read-only double)
deltaZ
Z-axis scroll amount (read-only double)
deltaMode
Unit for deltas: pixels (0), lines (1), or pages (2)
deltaMode constants
Constant
Value
Unit
WheelEvent.DOM_DELTA_PIXEL
0x00
Pixels
WheelEvent.DOM_DELTA_LINE
0x01
Lines
WheelEvent.DOM_DELTA_PAGE
0x02
Pages
Compare
⚖️ wheel vs Related Signals
Signal
Meaning
wheel
User rotated a wheel / trackpad (may or may not scroll)
scroll
Scroll position actually changed
scrollend
Scrolling finished (completion signal)
mousewheel
Deprecated & non-standard—use wheel instead
⚠️
MDN warning
A wheel event does not always cause scroll, and scroll is not always caused by wheel. Even when both fire, delta* may not match content scroll direction—read scrollLeft / scrollTop on scroll instead.
Performance
⚡ Passive Listeners & Cancelability
Canceling wheel (via preventDefault()) can stop scrolling or zooming. MDN notes that in some browsers only the first wheel event in a sequence is cancelable. Waiting on every wheel handler before scrolling can cause jank.
Observing only? Use addEventListener("wheel", fn, { passive: true }).
Need to cancel (custom zoom, custom scroll)? Use { passive: false } and call preventDefault() carefully.
Keep handlers light—wheel can fire at a high rate on trackpads.
wheel is marked Limited availability on MDN (not Baseline). Logos use the shared browser-image-sprite.png sprite from this project. Desktop browsers are strong; Safari on iOS typically does not expose Element wheel—pair with scroll for mobile scroll UIs.
✓ Limited availability
Element wheel
Fires on mouse wheel / trackpad rotation. Chrome, Firefox, Edge, Opera, and desktop Safari support it; Safari iOS generally does not.
PartialNot Baseline
Google Chrome31+
Supported
Mozilla Firefox17+
Supported
Apple Safari7+ desktop · iOS no
Partial
Microsoft Edge12+
Supported
OperaChromium-based yes
Supported
Internet Explorer9+ (legacy)
Supported
wheelLimited
Bottom line: Use wheel for desktop wheel/trackpad intent and custom zoom. For “did content move?”, listen to scroll and read scrollTop/scrollLeft.
Wrap Up
Conclusion
wheel is the standard signal that a mouse wheel or trackpad rotated. Read WheelEvent deltas for intent, use passive listeners when you only observe, and rely on scroll when you need the real scroll direction.
Prefer { passive: true } for observe-only handlers
Check deltaMode when normalizing deltas
Use scroll for scroll direction / position
Set { passive: false } only when you must cancel
❌ Don’t
Assume wheel always causes scroll
Treat deltaY as scroll direction truth
Call preventDefault() with a passive listener
Expect Safari iOS to fire Element wheel
Overwrite onwheel if you need multiple listeners
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about wheel
Wheel rotated—deltas for intent, scroll for position.
5
Core concepts
🖱01
On wheel
device rotated
Trigger
📄02
WheelEvent
deltaX / deltaY
API
⇄03
vs scroll
intent ≠ offset
Compare
⚡04
Passive
smooth scrolling
Perf
🎯05
Limited
not Baseline
Status
❓ Frequently Asked Questions
It fires when the user rotates a wheel button on a pointing device (typically a mouse), or uses related inputs such as a trackpad that simulate wheel actions. The event type is WheelEvent.
No. MDN does not mark Element wheel as Deprecated, Experimental, or Non-standard. It has Limited availability (not Baseline), mainly because Safari on iOS does not support it. It replaces the deprecated non-standard mousewheel event.
A WheelEvent, which inherits from MouseEvent, UIEvent, and Event. Useful read-only properties include deltaX, deltaY, deltaZ, and deltaMode.
wheel means the user rotated a wheel or trackpad — it may or may not scroll. scroll means the scroll offset actually changed. Zoom gestures can fire wheel with ctrlKey true. Keyboard or scrollbar scrolling can fire scroll without wheel.
No. MDN warns that even when wheel triggers scrolling, delta* values do not necessarily match content scroll direction. Prefer watching scrollLeft / scrollTop on the scroll event.
When you only observe the wheel and do not call preventDefault(). Passive listeners let the browser scroll without waiting on your handler, which avoids jank. Use { passive: false } only when you must cancel the event (for example custom zoom).
Did you know?
Ctrl + wheel / trackpad pinch often fires wheel with ctrlKey === true. That is how many apps detect zoom intent without waiting for a separate gesture API.