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.

June 10, 20264 min read8 / 17

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:

JavaScript
element.addEventListener('touchstart', handler) // finger lands element.addEventListener('touchend', handler) // finger lifts element.addEventListener('touchmove', handler) // finger drags element.addEventListener('touchcancel', handler) // OS interrupted

What 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:

JavaScript
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.

JavaScript
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:

Plain text
pointerdown pointerup pointermove pointercancel pointerover pointerout pointerenter pointerleave

The 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.

Touch events vs Pointer events: array model vs per-pointer calls, and what data each exposes 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.

JavaScript
// 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

  1. Mouse events fail on touch because: no persistent cursor, multi-touch, and optional pressure/tilt data.
  2. Touch events (Apple, 2009): single callback with an array of touches. touchcancel fires when the OS interrupts.
  3. Pointer events (W3C): one callback per pointer. Works for mouse, finger, and pen in a single event handler. Use pointerType to know which.
  4. iPhone max 5 touches, iPad 11, Android 4–8.
  5. For new code, use pointer events. They work everywhere and handle all input types.

Further Reading and Watching