Touch and pointer gestures
pointer events with touch-action
Chrome55
Edge12
Firefox59
Safari13
Features it needs
- Pointer EventsWidely available
hammerjs was written when mouse and touch were separate event streams that had to be normalised, and it has not been maintained since 2016. Pointer events deliver both through one set of handlers, with pointerId to tell fingers apart and setPointerCapture so a drag keeps reporting after the pointer leaves the element. A swipe is a pointerdown coordinate, a pointerup coordinate, and a threshold.
When this applies
Handling swipes, drags or other pointer gestures.
The native approach
let startX = 0;
el.addEventListener("pointerdown", (event) => {
startX = event.clientX;
// Keeps events coming even if the pointer leaves the element.
el.setPointerCapture(event.pointerId);
});
el.addEventListener("pointerup", (event) => {
const dx = event.clientX - startX;
if (Math.abs(dx) > 50) onSwipe(dx > 0 ? "right" : "left");
});
// Tell the browser which direction you are handling, so it keeps
// vertical scrolling for itself. In CSS: touch-action: pan-y.
el.style.touchAction = "pan-y";When the dependency is still right
An answer that always says "the platform covers it" is worse than no answer. These are the cases where this one does not hold.
- You need multi-touch recognisers such as pinch to zoom or two-finger rotate. Tracking several pointerIds and deriving the transform between them is real geometry, and it is most of what hammerjs is.
- You need velocity, direction and threshold tuning that already feels right. A naive distance check fires on a slow drag that was never meant as a swipe, and the tuned version is the library's actual value.
- You rely on hammerjs recognisers with conflict resolution between them, such as pan and swipe on the same element, where the ordering is configured rather than written.
- Your support target reaches below Chrome 55, Firefox 59 or Safari 13, which came to pointer events considerably later than the others.
Signs it was hand-rolled
No package is involved in any of these, so nothing would match in a package.json. If the code looks like one of them, this rule applies anyway, and the conditions above still decide.
- paired touchstart and touchend listeners reading changedTouches[0].clientX to work out a swipe direction
- separate mousedown and touchstart branches doing the same thing, written because the two event streams disagree