useDraggable

A low-level pointer drag hook. It tracks the drag offset, keeps the pointer captured when it leaves the element and plays the drag sounds. Window and useSlotDrag build on it.

import { useDraggable } from 'jarvis-react-ui';

const { onPointerDown, dragging } = useDraggable({ onStart, onMove, onEnd, disabled });

Usage

Attach onPointerDown to the drag handle. onMove receives the live offset (dx, dy) from the drag start; commit the position in onEnd.

import { useState } from 'react';
import type { CSSProperties } from 'react';
import { Panel, useDraggable } from 'jarvis-react-ui';

export default function DragBox() {
    const [pos, setPos] = useState({ x: 0, y: 0 });
    const [live, setLive] = useState({ dx: 0, dy: 0 });

    const { onPointerDown, dragging } = useDraggable({
        onMove: (state) => setLive({ dx: state.dx, dy: state.dy }),
        onEnd: (state) => {
            setPos((p) => ({ x: p.x + state.dx, y: p.y + state.dy }));
            setLive({ dx: 0, dy: 0 });
        },
    });

    const offset = {
        '--x': `${pos.x + live.dx}px`,
        '--y': `${pos.y + live.dy}px`,
    } as CSSProperties;

    return (
        <div className="translate-x-[var(--x)] translate-y-[var(--y)]" style={offset}>
            <Panel title={dragging ? 'DRAGGING…' : 'DRAG ME'} className="w-[200px]">
                <div
                    role="presentation"
                    onPointerDown={onPointerDown}
                    className="cursor-grab select-none py-4 text-center text-[10px] text-text-secondary active:cursor-grabbing"
                >
                    Grab here · dx {live.dx} · dy {live.dy}
                </div>
            </Panel>
        </div>
    );
}

Options

Option Type Description
onStart (e: PointerEvent) => void Called when the drag begins.
onMove (state: DragState, e: PointerEvent) => void Called on every pointer move.
onEnd (state: DragState, e: PointerEvent) => void Called on pointer up.
disabled boolean Ignores pointer down while true.

DragState is { dragging, startX, startY, dx, dy }. The hook returns onPointerDown and the current dragging flag for styling.

Sound

Plays drag_start, loops drag_move while dragging and plays drag_end on release.

Accessibility

Pointer only. Offer a keyboard alternative (e.g. arrow buttons or a slot picker) when dragging is the only way to change a layout.

Related