Touch And Pointer Events
Touch events were Apple's invention and ship as an array. Pointer events are the W3C response and fire per finger. Both live on every modern phone. Here is when to use which.
Mouse events were designed for a single pointer with a persistent cursor.
They do not model touch well. A mouse always exists on screen -- the cursor never disappears. A finger appears, moves, and lifts. That is a fundamentally different thing. And with fingers, multiple pointers can exist at the same time.
Two separate APIs emerged to fill that gap. One from Apple, one from the W3C. Both sit in the green tier -- they work on every modern device.
Touch Events: Apple's Spec (2009)
Apple invented multi-touch gestures for the original iPhone. The touch events API came with it. When other vendors wanted to implement touch support, they ran into Apple's patents -- which is why the web community eventually standardized something separate.
The four events:
element.addEventListener('touchstart', handler) // finger lands
element.addEventListener('touchend', handler) // finger lifts
element.addEventListener('touchmove', handler) // finger drags
element.addEventListener('touchcancel', handler) // OS interruptedWhat is touchcancel? If a call comes in while a user has their finger on a button, the OS takes control of the screen. The touch that was in progress is now invalid. touchcancel fires to let you clean up -- the finger is still physically there but the browser has dropped it. Always handle it or your UI can get stuck in a "pressed" state.
The Array Model
Every touch event handler receives a single event with arrays:
element.addEventListener('touchmove', (e) => {
const touches = e.touches // all currently active touches
const changed = e.changedTouches // touches that changed this frame
for (const touch of changed) {
console.log(touch.clientX, touch.clientY, touch.force)
}
})Three fingers active = one event call with touches.length === 3.
How many simultaneous touches can you track? It depends on hardware. iPhone typically supports five. iPad supports eleven. Android varies between four and eight depending on the manufacturer's hardware. The limit is physical -- the digitizer in the screen.
What Touch Events Do Not Support
Touch events only work with touch screens. They will not fire from a mouse or a stylus. There is also no standard way to get pressure on iOS -- Apple added force touch to older iPhones, then removed it. The hardware exists on MacBook trackpads, but touch events from a touchscreen don't carry it.
Pointer Events: The W3C Standard
Pointer events treat every kind of pointing device -- finger, mouse, stylus -- the same way. You write one set of handlers and they work for all input types.
element.addEventListener('pointerdown', (e) => {
console.log(e.pointerType) // "mouse" | "touch" | "pen"
console.log(e.pointerId) // unique ID per active pointer
console.log(e.pressure) // 0–1, if hardware supports it
console.log(e.tiltX, e.tiltY, e.twist) // pen/stylus metadata
})The event names mirror mouse events exactly, prefixed with pointer:
pointerdown pointerup pointermove pointercancel
pointerover pointerout pointerenter pointerleaveThe per-pointer model: three fingers active = three separate event calls, each with its own pointerId. You track multi-touch by maintaining a map of pointerId → state, rather than iterating an array.
pointerType tells you what fired the event. An Apple Pencil or Samsung S Pen will send "pen", and if the hardware supports it, e.pressure, e.tiltX, e.tiltY, and e.twist carry the stylus metadata. This is how drawing apps work on the web.
ExpandTouch events vs Pointer events: array model vs per-pointer calls, and what data each exposes
Which API to Use
Both APIs exist on every modern mobile device. For new code, prefer pointer events. They handle all input types with one set of handlers, the W3C standard is stable, and they give you more metadata.
The one case to reach for touch events is when you specifically need the full array of all active touches in a single callback -- certain gesture recognition algorithms are cleaner with the array model. Otherwise, pointer events are the better default.
// Prefer pointer events for new code
element.addEventListener('pointerdown', onStart)
element.addEventListener('pointermove', onMove)
element.addEventListener('pointerup', onEnd)
element.addEventListener('pointercancel', onCancel)Touch and pointer events cover fingers and styluses. There is one more input surface that has caused mobile developers grief since the first iPhone: the virtual keyboard. It appears and disappears, takes up unpredictable space, and the browser gives you almost no control over how your layout responds.
The Essentials
- Mouse events fail on touch because: no persistent cursor, multi-touch, and optional pressure/tilt data.
- Touch events (Apple, 2009): single callback with an array of touches.
touchcancelfires when the OS interrupts. - Pointer events (W3C): one callback per pointer. Works for mouse, finger, and pen in a single event handler. Use
pointerTypeto know which. - iPhone max 5 touches, iPad 11, Android 4–8.
- For new code, use pointer events. They work everywhere and handle all input types.
Further Reading and Watching
- Learn Pointer Events In 15 Minutes (YouTube) -- Web Dev Simplified walkthrough of pointerdown/pointermove/pointerup with live examples
- Learn JavaScript Touch Events In 17 Minutes (YouTube) -- same channel's companion video focused on the touch events API and touchcancel handling
Keep reading