# useDrag

Calls `onDrag` while the user drags an element with a mouse, finger, or pen. Returns a callback ref for the element (the handle).

Captures the pointer, so the drag keeps going when the pointer leaves the element or the window, and ends on release or cancel. Movements under `threshold` don't start a drag, so a click on the handle stays a click. Text selection is blocked while dragging. Always calls the latest `onDrag`.

## Import

```ts
import { useDrag } from '@vincent.ri/react-tils'
// or only this hook
import { useDrag } from '@vincent.ri/react-tils/useDrag'
```

## Usage

```ts
// A splitter that resizes the sidebar.
const [width, setWidth] = useState(280)
const handle = useDrag(({ deltaX }) => setWidth((w) => Math.min(600, Math.max(160, w + deltaX))))
return (
  <div style={{ display: 'flex' }}>
    <aside style={{ width }}>…</aside>
    <div ref={handle} role="separator" style={{ width: 6, cursor: 'col-resize', touchAction: 'none' }} />
    <main>…</main>
  </div>
)
```

## When to use it

Resizable panels and splitters, custom sliders, dragging items on a canvas or board, or pan to scroll.

## When not to

You only need to know a swipe happened and its direction; use `useSwipe`. For reordering lists, a drag-and-drop library handles keyboard access and drop targets. Give touch handles CSS `touch-action: none`, or the browser scrolls instead of dragging.

## API

```ts
function useDrag<T extends HTMLElement = HTMLElement>(onDrag: (drag: DragState) => void, options?: DragOptions): (element: T | null) => void
```

| Parameter | Description |
| --- | --- |
| `onDrag` | Called on every move with `dx`, `dy`, `deltaX`, `deltaY`, `first`, `last`, and the event. Can change every render. |
| `options` | `enabled`, `threshold`. Optional. |

**Returns** A callback ref. Pass it to the element to drag.

### Types

```ts
export type DragState = {
  /** Distance moved since the drag started, in pixels. */
  dx: number;
  dy: number;
  /** Distance moved since the previous call. */
  deltaX: number;
  deltaY: number;
  /** The first call of this drag. */
  first: boolean;
  /** The last call: the pointer was released or the drag was cancelled. */
  last: boolean;
  event: PointerEvent;
};
export type DragOptions = {
  /** Listen while `true`. Default `true`. */
  enabled?: boolean;
  /** Pixels the pointer must move before a drag starts, so clicks stay clicks. Default `3`. */
  threshold?: number;
};
```

## Browser support

Works in all modern browsers.

## Coming from another library?

Other libraries call this `useDraggable`, `useGesture` (`onDrag`), `usePointerDrag`.

---

495 B minified and brotlied
Source: https://github.com/vincentri/react-tils/blob/main/src/useDrag.ts
Docs page: https://vincentri.github.io/react-tils/hooks/useDrag/
Previous: [useSwipe](https://vincentri.github.io/react-tils/hooks/useSwipe.md)
Next: [usePointerPosition](https://vincentri.github.io/react-tils/hooks/usePointerPosition.md)
