React hook for handling swipe gestures on touch devices and mouse interactions with comprehensive directional callbacks and customizable sensitivity settings
npx @tessl/cli install tessl/npm-react-swipeable@7.0.0React Swipeable is a React hook that provides comprehensive swipe gesture detection for touch devices and mouse interactions. It offers directional swipe callbacks, customizable sensitivity settings, velocity calculations, and supports both touch and mouse events with minimal performance impact.
npm install react-swipeableimport { useSwipeable } from "react-swipeable";Import with types:
import { useSwipeable, SwipeableProps, SwipeEventData, LEFT, RIGHT, UP, DOWN } from "react-swipeable";For CommonJS:
const { useSwipeable } = require("react-swipeable");import { useSwipeable } from "react-swipeable";
function SwipeExample() {
const handlers = useSwipeable({
onSwiped: (eventData) => console.log("User swiped!", eventData),
onSwipedLeft: () => console.log("User swiped left!"),
onSwipedRight: () => console.log("User swiped right!"),
preventScrollOnSwipe: true,
trackMouse: true
});
return <div {...handlers}>Swipe me!</div>;
}React Swipeable is built around a single React hook that follows these key patterns:
useSwipeable hook returns event handlers to attach to target elementsThe main hook for detecting and handling swipe gestures on React elements.
/**
* React hook for handling swipe gestures on touch devices and mouse interactions
* @param options - Configuration and callback options
* @returns Event handlers to spread onto target element
*/
function useSwipeable(options: SwipeableProps): SwipeableHandlers;
interface SwipeableHandlers {
/** Ref callback to attach to target element */
ref(element: HTMLElement | null): void;
/** Optional mouse down handler (present when trackMouse is true) */
onMouseDown?(event: React.MouseEvent): void;
}All configuration options for customizing swipe behavior.
interface SwipeableProps {
// Event Callbacks
/** Called at start of a tracked swipe */
onSwipeStart?: SwipeCallback;
/** Called for each move event during a tracked swipe */
onSwiping?: SwipeCallback;
/** Called after any swipe */
onSwiped?: SwipeCallback;
/** Called after a LEFT swipe */
onSwipedLeft?: SwipeCallback;
/** Called after a RIGHT swipe */
onSwipedRight?: SwipeCallback;
/** Called after a UP swipe */
onSwipedUp?: SwipeCallback;
/** Called after a DOWN swipe */
onSwipedDown?: SwipeCallback;
/** Called after a tap (touch under min distance) */
onTap?: TapCallback;
/** Called for touchstart and mousedown events */
onTouchStartOrOnMouseDown?: TapCallback;
/** Called for touchend and mouseup events */
onTouchEndOrOnMouseUp?: TapCallback;
// Configuration Options
/** Min distance (px) before a swipe starts. Default: 10 */
delta?: number | { [key in Lowercase<SwipeDirections>]?: number };
/** Prevents scroll during swipe in most cases. Default: false */
preventScrollOnSwipe?: boolean;
/** Set a rotation angle for coordinate system. Default: 0 */
rotationAngle?: number;
/** Track mouse input. Default: false */
trackMouse?: boolean;
/** Track touch input. Default: true */
trackTouch?: boolean;
/** Allowable duration of a swipe (ms). Default: Infinity */
swipeDuration?: number;
/** Options for touch event listeners. Default: { passive: true } */
touchEventOptions?: { passive: boolean };
}Data provided to swipe event callbacks containing comprehensive gesture information.
interface SwipeEventData {
/** Absolute displacement of swipe in x direction */
absX: number;
/** Absolute displacement of swipe in y direction */
absY: number;
/** Displacement of swipe in x direction (current.x - initial.x) */
deltaX: number;
/** Displacement of swipe in y direction (current.y - initial.y) */
deltaY: number;
/** Direction of swipe - Left | Right | Up | Down */
dir: SwipeDirections;
/** Source event object */
event: HandledEvents;
/** True for the first event of a tracked swipe */
first: boolean;
/** Location where swipe started - [x, y] */
initial: Vector2;
/** Absolute velocity (speed) - √(absX² + absY²) / time */
velocity: number;
/** Velocity per axis - [deltaX/time, deltaY/time] */
vxvy: Vector2;
}Function signatures for swipe and tap event callbacks.
/** Callback function for swipe events */
type SwipeCallback = (eventData: SwipeEventData) => void;
/** Callback function for tap events */
type TapCallback = ({ event }: { event: HandledEvents }) => void;
/** Interface containing all directional swipe callbacks */
interface SwipeableDirectionCallbacks {
/** Called after a DOWN swipe */
onSwipedDown?: SwipeCallback;
/** Called after a LEFT swipe */
onSwipedLeft?: SwipeCallback;
/** Called after a RIGHT swipe */
onSwipedRight?: SwipeCallback;
/** Called after a UP swipe */
onSwipedUp?: SwipeCallback;
}Constants for swipe directions.
/** Left swipe direction constant */
const LEFT = "Left";
/** Right swipe direction constant */
const RIGHT = "Right";
/** Up swipe direction constant */
const UP = "Up";
/** Down swipe direction constant */
const DOWN = "Down";
/** Union type for all swipe directions */
type SwipeDirections = typeof LEFT | typeof RIGHT | typeof UP | typeof DOWN;Additional utility types used by the library.
/** Two-dimensional vector for coordinates */
type Vector2 = [number, number];
/** Event types handled by the library */
type HandledEvents = React.MouseEvent | TouchEvent | MouseEvent;import { useSwipeable } from "react-swipeable";
function ImageCarousel() {
const [currentIndex, setCurrentIndex] = useState(0);
const handlers = useSwipeable({
onSwipedLeft: () => setCurrentIndex(prev => prev + 1),
onSwipedRight: () => setCurrentIndex(prev => prev - 1),
preventScrollOnSwipe: true,
trackMouse: true
});
return <div {...handlers}>Image content here</div>;
}import { useSwipeable, SwipeEventData } from "react-swipeable";
function AdvancedSwipeHandler() {
const handlers = useSwipeable({
onSwiping: (eventData: SwipeEventData) => {
// Track swipe progress
console.log(`Swiping ${eventData.dir}: ${eventData.absX}px, ${eventData.absY}px`);
console.log(`Velocity: ${eventData.velocity}`);
},
onSwiped: (eventData: SwipeEventData) => {
// Handle completed swipe
if (eventData.velocity > 0.5) {
console.log("Fast swipe detected!");
}
},
delta: { left: 50, right: 50, up: 20, down: 20 }, // Different thresholds per direction
swipeDuration: 1000, // Maximum 1 second swipes
preventScrollOnSwipe: true,
trackMouse: true
});
return <div {...handlers}>Advanced swipe area</div>;
}import { useSwipeable } from "react-swipeable";
function MobileNav({ isOpen, onToggle }: { isOpen: boolean; onToggle: (open: boolean) => void }) {
const handlers = useSwipeable({
onSwipedLeft: () => onToggle(false), // Close menu
onSwipedRight: () => onToggle(true), // Open menu
trackTouch: true,
trackMouse: false, // Touch only for mobile
preventScrollOnSwipe: true,
delta: 30 // Require 30px minimum swipe
});
return (
<div {...handlers} className={`nav-menu ${isOpen ? 'open' : 'closed'}`}>
Navigation content
</div>
);
}import { useSwipeable, LEFT, RIGHT, UP, DOWN } from "react-swipeable";
function GameControls({ onMove }: { onMove: (direction: string) => void }) {
const handlers = useSwipeable({
onSwipedLeft: () => onMove(LEFT),
onSwipedRight: () => onMove(RIGHT),
onSwipedUp: () => onMove(UP),
onSwipedDown: () => onMove(DOWN),
onTap: () => console.log("Tap detected - maybe pause?"),
delta: 20,
swipeDuration: 500, // Quick swipes only
preventScrollOnSwipe: true,
trackMouse: true // Support both touch and mouse
});
return <div {...handlers} className="game-controls">Game area</div>;
}