useGesture
useGesture attaches a Gesture.* descriptor to an element, window, or an
array of elements. Config and handlers stay live across renders, so editing
them after mount takes effect without re-attaching listeners.
useGesture(ref, descriptor);
useGesture(window, descriptor);
useGesture(refs, descriptor | ((index: number) => descriptor));
Every Gesture.*() call returns a chainable builder. Call .onStart(),
.onChange(), .onEnd() (and, where relevant, .onFinalize() or
.onSwipe()) plus any config methods, then pass the built descriptor to
useGesture.
Gesture.Pan()
Streams a full press-move-release cycle. useDrag is built on this. Reach
for Gesture.Pan() directly when you need drag data without useDrag's
built-in spring/decay behavior.
import { useRef } from 'react';
import { Gesture, useGesture, useValue, animate } from 'react-ui-animate';
function Panner() {
const ref = useRef(null);
const [x, setX] = useValue(0);
/* Stream pan movement into an animated value */
useGesture(
ref,
Gesture.Pan()
.onChange(({ down, movement }) => setX(movement.x))
.onEnd(() => setX(0))
);
return <animate.div ref={ref} style={{ translateX: x }} />;
}
Config: .enabled(bool), .minDistance(px), .axis('x' | 'y').
Event shape: { phase, down, movement, offset, velocity, event, target, cancel }.
Gesture.Move()
Tracks pointer position with no press required: cursor-follow effects, magnetic hover.
useGesture(
window,
Gesture.Move().onChange(({ offset }) => setCursor(offset))
);
Event shape: { movement, offset, velocity, event, cancel }.
Gesture.Wheel()
Trackpad/mouse-wheel deltas, for custom zoom or horizontal scroll.
useGesture(
ref,
Gesture.Wheel().onChange(({ movement }) => setZoom((z) => z - movement.y * 0.001))
);
Event shape: { movement, offset, velocity, event, cancel }.
Gesture.Scroll()
Native scroll events with movement/velocity, for scroll-linked animation and
progress bars. (For intersection-based reveal-on-scroll, see
useInView or the view prop
instead: Gesture.Scroll() is for continuous scroll position, not
enter/exit detection.)
useGesture(
window,
Gesture.Scroll().onChange(({ offset }) => {
const max = document.documentElement.scrollHeight - window.innerHeight;
setProgress(offset.y / max);
})
);
Event shape: { movement, offset, velocity, event, cancel }.
Gesture.Swipe()
A fast, short, directional flick resolved once at release. Not a stream:
only onSwipe fires, and only if the release clears both thresholds.
useGesture(
ref,
Gesture.Swipe()
.distanceThreshold(40)
.onSwipe(({ direction }) => {
if (direction === 'left') goNext();
if (direction === 'right') goBack();
})
);
Config: .enabled(bool), .axis('x' | 'y'), .velocityThreshold(pxPerMs)
(default 0.5), .distanceThreshold(px) (default 30).
Event shape: { direction, movement, velocity, event, target }.
Gesture.Hover()
Enter/leave/move-while-over: deliberately leaner than Gesture.Move() (no
movement/velocity). Use Gesture.Move() instead if you need those while
hovering.
useGesture(
ref,
Gesture.Hover().onChange(({ hovering }) => setIsHovering(hovering))
);
Event shape: { hovering, offset, event, target }.
Gesture.Pinch()
Two-finger pinch-to-zoom. scale is the current pointer-pair distance
relative to where the gesture began.
useGesture(
ref,
Gesture.Pinch().onChange(({ scale }) => setZoom(scale))
);
Config: .enabled(bool), .threshold(v) (minimum |scale - 1| before
recognized as active, default 0.02).
Event shape: { phase, scale, velocity, center, event, target, cancel }.
Gesture.Rotate()
Two-finger rotation, in degrees from the pointer pair's starting angle.
Gesture.Pinch() and Gesture.Rotate() can both be registered on the same
ref to read scale and rotation from one two-finger gesture.
useGesture(
ref,
Gesture.Rotate().onChange(({ rotation }) => setAngle(rotation))
);
Config: .enabled(bool), .threshold(degrees) (minimum rotation before
recognized as active, default 2).
Event shape: { phase, rotation, velocity, center, event, target, cancel }.
Array mode
Passing an array of refs registers each one individually, diffed by ref
identity (not array length). Reordering or adding/removing refs doesn't
tear down unrelated registrations. Every emitted event gets index merged
in:
useGesture(
cardRefs,
(index) => Gesture.Pan().onChange(({ movement, index }) => setX(index, movement.x))
);