Skip to content

Repository files navigation

Tocada JS

npm versionnpm downloadsCIcodecovLicense: MIT

Pointer and touch gestures with ease

For the most up-to-date documentation, see the Tocada GitHub repository.

Installation

npm install tocada

Basic Usage

import{usePointerEvents}from"tocada";// Pass a query selector or HTMLElement (Pointer Events by default: mouse, pen, touch)constswipeArea=usePointerEvents("#my-element");// Listen for eventsswipeArea.element.addEventListener("swipe",(e)=>{console.log("Swiped!",e.detail);});// Clean up when doneswipeArea.destroy();

For TouchEvent-only input (legacy mobile pipelines), use useTouchEvents instead—it forces pointerEvents: false.

new Tocada(selectorOrElement) is the same as passing { pointerEvents: true } (Pointer Events). Use { pointerEvents: false } or useTouchEvents(...) only when you need the legacy touch stack.

Available Events

Single-contact events

EventDescription
tapQuick touch < 200ms
doubletapTwo taps within 300ms
pressTouch held 200-500ms
holdTouch held > 500ms
swipeFires before directional swipe events (same gesture also emits swipeup / swipedown / etc.)
swipeupSwipe in upward direction
swipedownSwipe in downward direction
swipeleftSwipe in left direction
swiperightSwipe in right direction
swipeclockwiseCircular swipe in clockwise direction
swipecounterclockwiseCircular swipe in counter-clockwise direction

Multi-contact events

EventDescription
gestureFires before any multi-contact gesture (touchCount is active pointer / touch count)
pinchTwo fingers moving closer together
spreadTwo fingers moving apart
rotateTwo-finger rotation (fires before directional)
rotateclockwiseClockwise two-finger rotation
rotatecounterclockwiseCounter-clockwise two-finger rotation

Configuration Options

import{usePointerEvents}from"tocada";constswipeArea=usePointerEvents("#my-element",{// Prefix all event names (e.g., "myapp-swipe", "myapp-tap")eventPrefix: "myapp-",// Enable high-precision element tracking (fills gaps between move events)// Adds computational overhead - use when you need complete element coverageuseHighPrecision: true,// Inline touch-action on the target element (default: "none").// Suppresses native pan/pinch on that surface so gestures stay accurate; restored on destroy().// Use false to leave touch-action unchanged, or a CSS value (e.g. "manipulation", "pan-y").touchAction: "none",// Customize detection thresholdsthresholds: {swipeThreshold: 50,// Min distance for swipe (px)tapMaxTime: 200,// Max duration for tap (ms)doubleTapGap: 300,// Max gap between taps for doubletap (ms)pressMinTime: 200,// Min duration for press (ms)holdMinTime: 500,// Min duration for hold (ms)circularSwipeMinArc: 90,// Min arc for circular swipe (degrees)// NOT YET IMPLEMENTED palmMinTouches: 3, // Min touch points for palm swipe// NOT YET IMPLEMENTED palmLineTolerance: 50, // Tolerance for palm line detection (px)rotateMinAngle: 15,// Min angle for rotation (degrees)pinchSpreadMinDistance: 20,// Min finger distance change for pinch/spread (px)}});// With prefix, listen like this:swipeArea.element.addEventListener("myapp-swipe",(e)=>{console.log("Swiped!",e.detail);});

touch-action and scrolling

By default, Tocada sets touch-action: none on the element’s inline style so the browser does not steal the gesture for native pan/zoom while you track pointers or touches. The previous inline value is restored when you call destroy() (or the property is removed if there was none).

OptionBehavior
(omitted)Sets touch-action: none
touchAction: falseDoes not change touch-action (use when the region must scroll or zoom normally)
touchAction: "pan-y" (etc.)Sets that keyword; still restored on destroy()

This applies to new Tocada(...), usePointerEvents(...), and useTouchEvents(...).

Event Details

Each event type provides a detail object with relevant data.

Swipe Events (swipe, swipeup, swipedown, swipeleft, swiperight)

{velocity,// Overall speed (px/ms)velocityX,// X-axis speedvelocityY,// Y-axis speeddistance,// Total distance traveleddistanceX,// X-axis distancedistanceY,// Y-axis distanceavgPressure,// Average touch pressurestartPressure,// Starting pressureendPressure,// Ending pressurestartTime,// Start timestampendTime,// End timestampstartingElement,// First element touchedendingElement,// Last element touchedtouchedElements,// All elements touched during swipestartingCoords,// { x, y } start positionendingCoords,// { x, y } end position// High precision fields (only when useHighPrecision: true)touchedPathElements?,// Elements found by sampling touchPath coordinatesinterpolatedTouchedElements?,// Elements found via interpolation between touchmove eventsderivedTouchedElements?,// Combined and chronologically ordered array (recommended)}

Tap Events (tap, doubletap, press, hold)

{duration,// How long the touch lasted (ms)pressure,// Touch pressureelement,// Element that was tappedcoords,// { x, y } tap positionstartTime,// Start timestampendTime,// End timestamp}

Circular Swipe Events (swipeclockwise, swipecounterclockwise)

Detection uses sampled move points plus the lift position (pointer up / touch end), and denoises dense or jittery input so direction stays stable. Tune sensitivity with thresholds.circularSwipeMinArc (default 90 degrees).

{direction,// "clockwise" or "counterclockwise"arc,// Total arc traversed (degrees)touchPath,// Array of { x, y, time } pointstouchedElements,// All elements touched during circular swipe// High precision fields (only when useHighPrecision: true)touchedPathElements?,// Elements found by sampling touchPath coordinatesinterpolatedTouchedElements?,// Elements found via interpolation between touchmove eventsderivedTouchedElements?,// Combined and chronologically ordered array (recommended)}

Rotate Events (rotate, rotateclockwise, rotatecounterclockwise)

{angle,// Total rotation (degrees)direction,// "clockwise" or "counterclockwise"startAngle,// Starting angleendAngle,// Ending anglecenterPoint,// { x, y } center of rotation}

Pinch/Spread Events (pinch, spread)

{gesture,// "pinch" or "spread"startDistance,// Initial distance between fingersendDistance,// Final distance between fingersdistanceChange,// Change in distancescale,// endDistance / startDistancecenterPoint,// { x, y } center point}

Gesture Event (gesture)

{touchCount,// Active contacts (pointers or touches, depending on pipeline)}

High precision tracking

When useHighPrecision: true is enabled, Tocada provides additional element tracking arrays to fill gaps between discrete move samples (pointermove or touchmove, depending on pipeline) during rapid swipes. This is useful for:

  • Visual feedback: Highlighting all elements in a swipe path
  • Game interactions: Detecting all tiles/elements touched during a gesture
  • Complete coverage: Ensuring no elements are missed during fast swipes

Usage

constswipeArea=usePointerEvents("#my-element",{useHighPrecision: true});swipeArea.element.addEventListener("swipe",(e)=>{// Use derivedTouchedElements for complete, ordered coverageconstallElements=e.detail.derivedTouchedElements||e.detail.touchedElements;allElements.forEach(el=>el.classList.add("highlighted"));});

Available Arrays

When useHighPrecision: true, three additional arrays are provided:

  • touchedPathElements: Elements found by sampling coordinates from the touchPath array. This fills gaps by checking elements at points along the recorded touch path.

  • interpolatedTouchedElements: Elements found via interpolation between consecutive move events. Samples points every 5–10px along the interpolation path to catch elements that might have been missed.

  • derivedTouchedElements: Recommended to use. A combined array that merges touchedElements, interpolatedTouchedElements, and touchedPathElements, then orders them chronologically by their position in the touch path and deduplicates them.

Performance Considerations

High precision tracking adds computational overhead as it:

  • Samples multiple points along the path
  • Calls document.elementFromPoint() for each sampled point
  • Performs interpolation calculations during move events

Only enable this feature when you need complete element coverage. For most use cases, the standard touchedElements array is sufficient.

Native Browser Alternatives

For custom tracking needs or edge cases, you can use native browser APIs:

  • document.elementFromPoint(x, y): Get the topmost element at specific coordinates
  • document.elementsFromPoint(x, y): Get all elements at coordinates (in stack order)
  • PointerEvent: When using the default pointer pipeline, pressure, pointerId, and coalesced move events are available from the browser.
  • TouchEvent.touches (touch pipeline only): Access raw touch data during move events
  • TouchEvent.changedTouches (touch pipeline only): Touches that changed in the current event

These native APIs can be useful for:

  • Custom interpolation logic
  • Handling edge cases not covered by Tocada
  • Building specialized gesture tracking features
  • Debugging pointer or touch behavior

TypeScript Support

Tocada is written in TypeScript and exports all types:

importTocada,{usePointerEvents,useTouchEvents,ITocadaOptions,// includes touchAction?: false | stringISwipeEventDetails,ITapEventDetails,IRotateEventDetails,IPinchSpreadEventDetails,// IPalmSwipeEventDetails, NOT YET IMPLEMENTEDICircularSwipeEventDetails,DEFAULT_THRESHOLDS,}from"tocada";

Help Me Out

I write a lot of open source software (some more useful than others). You can help me out by tossing me a few bucks to buy coffee.

Buy Me A Coffee

About

JS Touch Events!

Resources

Contributing

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages