---
title: "useDraggable – Element Hook Usage & Examples"
description: "Make elements draggable."
canonical: https://reactuse.com/element/usedraggable/
---

# useDraggable

Make elements draggable

`useDraggable` makes any HTML or SVG element draggable by tracking pointer events and returning the current `x` and `y` position, a boolean indicating whether the element is being dragged, and a function to programmatically set the position. It supports pointer, mouse, touch, and pen inputs, and can optionally constrain movement within a container element.

### When to Use

- Building draggable panels, floating toolbars, or resizable widgets
- Implementing drag-to-reposition functionality for dashboard cards or kanban items
- Creating interactive diagrams or editors where elements need free movement

### Notes

- **Touch support**: Set `touch-action: none` on the draggable element's CSS to prevent browser scroll interference on touch devices.
- **Container bounds**: Use the `containerElement` option to restrict dragging within a parent element. The hook will calculate bounds automatically.
- **Callbacks**: The `onStart`, `onMove`, and `onEnd` callbacks give you fine-grained control. Returning `false` from `onStart` prevents the drag from beginning.
- **Cleanup**: All pointer event listeners are removed automatically on unmount.

## Usage

### Fixed Demo

```tsx live
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>
  );
};

```

### Relative Demo

```tsx live
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>
  );
};

```

%%API%%