useDraggable
Make elements draggable
Usage
Fixed Demo
Live Editor
function Demo() { const el = useRef<HTMLDivElement>(null); const [initialValue, setInitialValue] = useState({ x: 200 / 2.2, y: 120 }); useEffect(() => { setInitialValue({ x: window.innerWidth / 2.2, y: 120 }); }, []); const [x, y, isDragging] = useDraggable(el, { initialValue, preventDefault: true, }); return ( <div> <p style={{ textAlign: "center" }}>Check the floating boxes</p> <div ref={el} style={{ position: "fixed", cursor: "move", zIndex: 10, touchAction: "none", padding: 10, border: "solid 1px", left: x, top: y, }} > {isDragging ? "Dragging!" : "👋 Drag me!"} <div> I am at {Math.round(x)}, {Math.round(y)} </div> </div> </div> ); }
Result
Loading...
Relative Demo
Live Editor
function Demo() { const el = useRef<HTMLDivElement>(null); const scope = useRef<HTMLDivElement>(null); const initialValue = { x: 200 / 2.2, y: 120 }; const [x, y, isDragging, setPosition] = useDraggable(el, { initialValue, preventDefault: true, containerElement: scope, }); return ( <div ref={scope} style={{ width: 500, height: 500, border: "1px solid blue", position: "relative", }} > <button style={{ textAlign: "center" }} onClick={() => { setPosition({ x: 250, y: 250, }); }} > Set Position </button> <div ref={el} style={{ position: "absolute", cursor: "move", zIndex: 10, touchAction: "none", padding: 10, border: "solid 1px", left: x, top: y, whiteSpace: "nowrap", }} > {isDragging ? "Dragging!" : "👋 Drag me!"} <div style={{ whiteSpace: "nowrap" }}> I am at {Math.round(x)}, {Math.round(y)} </div> </div> </div> ); }
Result
Loading...
API
useDraggable
Returns
readonly [number, number, boolean, React.Dispatch<React.SetStateAction<Position>>]
: A tuple with the following elements:
- x
- y
- Whether the element is being dragged set the element position
Arguments
Argument | Description | Type | DefaultValue |
---|---|---|---|
target | dom element | BasicTarget<HTMLElement | SVGElement> (Required) | - |
options | optional params | UseDraggableOptions | undefined | - |
UseDraggableOptions
Property | Description | Type | DefaultValue |
---|---|---|---|
exact | Only start the dragging when click on the element directly | boolean | false |
preventDefault | Prevent events defaults | boolean | false |
stopPropagation | Prevent events propagation | boolean | false |
draggingElement | Element to attach pointermove and pointerup events to. | BasicTarget<HTMLElement | SVGElement> | window |
containerElement | Element for calculating bounds (If not set, it will use the event's target). | BasicTarget<HTMLElement | SVGAElement> | undefined |
handle | Handle that triggers the drag event | RefObject<HTMLElement | SVGElement> | target |
pointerTypes | Pointer types that listen to. | PointerType[] | ['mouse', 'touch', 'pen'] |
initialValue | Initial position of the element. | Position | { x: 0, y: 0 } |
onStart | Callback when the dragging starts. Return false to prevent dragging. | (position: Position, event: PointerEvent) => void | false | - |
onMove | Callback during dragging. | (position: Position, event: PointerEvent) => void | - |
onEnd | Callback when dragging end. | (position: Position, event: PointerEvent) => void | - |
BasicTarget
export type BasicTarget<T extends TargetType = Element> = (() => TargetValue<T>) | TargetValue<T> | MutableRefObject<TargetValue<T>>;
TargetValue
type TargetValue<T> = T | undefined | null;
TargetType
type TargetType = HTMLElement | Element | Window | Document | EventTarget;
PointerType
export type PointerType = 'mouse' | 'touch' | 'pen';
Position
export interface Position {
x: number;
y: number;
}