useDraggable
Tracks a pointer drag and exposes a CSS transform offset. It distinguishes a
tap from a drag with a small threshold (so a click still registers), and divides
movement by the rendered scale so dragging feels 1:1 even inside a zoomed
canvas. Mouse and pen drag; touch is reserved for canvas pan/zoom.
Drag me
Installation
npx shadcn@latest add https://canvas.blode.co/r/use-draggable.jsonUsage
const { ref, dragging, transform, onPointerDown, onPointerMove, onPointerUp } =
useDraggable();
return (
<div
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
ref={ref}
style={{ cursor: dragging ? "grabbing" : "grab", transform }}
>
Drag me
</div>
);onPointerUp returns true if the gesture was a drag and false if it was a
tap, handy for firing a click action only when the element wasn't moved.
Returns
| Prop | Type | Default | Description |
|---|---|---|---|
| ref | Ref<HTMLDivElement> | — | Attach to the draggable element. |
| transform | string | undefined | — | The current translate, for the element's `style.transform`. |
| dragging | boolean | — | True while an active drag is in progress. |
| onPointerDown | (e) => void | — | Pointer-down handler, starts tracking. |
| onPointerMove | (e) => void | — | Pointer-move handler, updates the offset. |
| onPointerUp | () => boolean | — | Pointer-up handler, returns whether it was a drag. |