Skip to main content
The React adapter provides additional hooks for accessing the drag and drop manager, monitoring events, and tracking drag operations.

useDragDropManager

Access the DragDropManager instance from anywhere within a DragDropProvider.

Usage

import {useDragDropManager} from '@dnd-kit/react';

function MyComponent() {
  const manager = useDragDropManager();

  return (
    <button onClick={() => manager?.dragOperation.cancel()}>
      Cancel Drag
    </button>
  );
}

Return Value

manager
DragDropManager | null
The DragDropManager instance, or null if called outside a DragDropProvider.The manager provides access to:
  • dragOperation — Current drag operation state
  • registry — Registry of draggables and droppables
  • monitor — Event monitor for subscribing to events
  • plugins — Active plugins
  • sensors — Active sensors
  • modifiers — Active modifiers

Example

function DragControls() {
  const manager = useDragDropManager();

  const cancelDrag = () => {
    manager?.dragOperation.cancel();
  };

  const isDragging = manager?.dragOperation.status.dragging ?? false;

  return (
    <div>
      <p>Status: {isDragging ? 'Dragging' : 'Idle'}</p>
      {isDragging && (
        <button onClick={cancelDrag}>Cancel</button>
      )}
    </div>
  );
}

Type Parameters

interface MyData {
  label: string;
}

const manager = useDragDropManager<MyData>();
// manager.dragOperation.source.data is typed as MyData

useDragDropMonitor

Monitor drag and drop events from anywhere within a DragDropProvider. This hook subscribes to events and automatically cleans up listeners when the component unmounts.

Usage

import {useDragDropMonitor} from '@dnd-kit/react';

function EventLogger() {
  useDragDropMonitor({
    onDragStart: (event, manager) => {
      console.log('Drag started:', event.operation.source.id);
    },
    onDragEnd: (event, manager) => {
      console.log('Drag ended:', event.operation.source.id);
    },
  });

  return <div>Check console for drag events</div>;
}

Parameters

handlers
Partial<EventHandlers>
required
Object containing event handlers for drag and drop events. All handlers are optional.Available handlers:
  • onBeforeDragStart
  • onDragStart
  • onDragMove
  • onDragOver
  • onDragEnd
  • onCollision

Event Handlers

onBeforeDragStart
(event: BeforeDragStartEvent, manager: DragDropManager) => void
Called before a drag operation starts.
useDragDropMonitor({
  onBeforeDragStart: (event) => {
    console.log('About to drag:', event.source.id);
  },
});
onDragStart
(event: DragStartEvent, manager: DragDropManager) => void
Called when a drag operation starts.
useDragDropMonitor({
  onDragStart: (event) => {
    setActiveId(event.operation.source.id);
  },
});
onDragMove
(event: DragMoveEvent, manager: DragDropManager) => void
Called continuously while dragging. Use sparingly as this fires frequently.
useDragDropMonitor({
  onDragMove: (event) => {
    setPosition(event.operation.position);
  },
});
onDragOver
(event: DragOverEvent, manager: DragDropManager) => void
Called when dragging over a droppable element.
useDragDropMonitor({
  onDragOver: (event) => {
    console.log('Over:', event.operation.target?.id);
  },
});
onDragEnd
(event: DragEndEvent, manager: DragDropManager) => void
Called when a drag operation ends.
useDragDropMonitor({
  onDragEnd: (event) => {
    if (!event.canceled) {
      handleDrop(event.operation.source, event.operation.target);
    }
  },
});
onCollision
(event: CollisionEvent, manager: DragDropManager) => void
Called when collision detection identifies potential drop targets.

Examples

Event Logger

function EventLogger() {
  const [events, setEvents] = useState([]);

  useDragDropMonitor({
    onDragStart: (event) => {
      setEvents((prev) => [...prev, `Started: ${event.operation.source.id}`]);
    },
    onDragOver: (event) => {
      setEvents((prev) => [
        ...prev,
        `Over: ${event.operation.target?.id ?? 'none'}`,
      ]);
    },
    onDragEnd: (event) => {
      setEvents((prev) => [
        ...prev,
        `Ended: ${event.canceled ? 'canceled' : 'completed'}`,
      ]);
    },
  });

  return (
    <div>
      <h3>Event Log</h3>
      <ul>
        {events.map((event, i) => (
          <li key={i}>{event}</li>
        ))}
      </ul>
    </div>
  );
}

State Synchronization

function DragStateSync() {
  const [isDragging, setIsDragging] = useState(false);
  const [currentTarget, setCurrentTarget] = useState(null);

  useDragDropMonitor({
    onDragStart: () => setIsDragging(true),
    onDragOver: (event) => setCurrentTarget(event.operation.target?.id),
    onDragEnd: () => {
      setIsDragging(false);
      setCurrentTarget(null);
    },
  });

  return (
    <div>
      <p>Dragging: {isDragging ? 'Yes' : 'No'}</p>
      <p>Target: {currentTarget ?? 'None'}</p>
    </div>
  );
}

Analytics Tracking

function AnalyticsTracker() {
  useDragDropMonitor({
    onDragEnd: (event) => {
      if (event.canceled) {
        analytics.track('drag_canceled', {
          sourceId: event.operation.source.id,
        });
      } else {
        analytics.track('drag_completed', {
          sourceId: event.operation.source.id,
          targetId: event.operation.target?.id,
        });
      }
    },
  });

  return null;
}

useDragOperation

Access the current drag operation state, including the drag source and target.

Usage

import {useDragOperation} from '@dnd-kit/react';

function DragStatus() {
  const {source, target} = useDragOperation();

  if (!source) {
    return <div>Not dragging</div>;
  }

  return (
    <div>
      <p>Dragging: {source.id}</p>
      <p>Target: {target?.id ?? 'None'}</p>
    </div>
  );
}

Return Value

source
Draggable | null
The draggable element currently being dragged, or null if no drag is active.
const {source} = useDragOperation();
console.log(source?.id, source?.data);
target
Droppable | null
The current drop target, or null if not over any droppable.
const {target} = useDragOperation();
console.log(target?.id, target?.data);

Examples

Drag Preview

function DragPreview() {
  const {source, target} = useDragOperation();

  if (!source) return null;

  return (
    <div
      style={{
        position: 'fixed',
        bottom: 20,
        right: 20,
        padding: '10px',
        background: 'white',
        border: '1px solid black',
        borderRadius: '4px',
      }}
    >
      <p>Dragging: {source.data.label}</p>
      {target ? (
        <p>Target: {target.data.label}</p>
      ) : (
        <p>No target</p>
      )}
    </div>
  );
}

Conditional Rendering

function DropHelper() {
  const {source, target} = useDragOperation();
  const canDrop = source && target && isCompatible(source, target);

  if (!source) return null;

  return (
    <div className="drop-helper">
      {canDrop ? (
        <span style={{color: 'green'}}>✓ Can drop here</span>
      ) : (
        <span style={{color: 'red'}}>✗ Cannot drop here</span>
      )}
    </div>
  );
}

function isCompatible(source, target) {
  return source.data.type === target.data.acceptType;
}

Global Drag Indicator

function GlobalDragIndicator() {
  const {source} = useDragOperation();

  if (!source) return null;

  return (
    <div
      style={{
        position: 'fixed',
        top: 0,
        left: 0,
        right: 0,
        padding: '10px',
        background: '#2196f3',
        color: 'white',
        textAlign: 'center',
        zIndex: 1000,
      }}
    >
      Dragging: {source.data.label}
    </div>
  );
}

Type Parameters

interface ItemData {
  label: string;
  category: string;
}

const {source, target} = useDragOperation<ItemData>();
// source.data and target.data are typed as ItemData

Type Safety

All hooks support TypeScript generics for type-safe data:
interface TaskData {
  title: string;
  priority: 'low' | 'medium' | 'high';
}

function TaskMonitor() {
  const manager = useDragDropManager<TaskData>();
  const {source, target} = useDragOperation<TaskData>();

  useDragDropMonitor<TaskData>({
    onDragEnd: (event) => {
      // event.operation.source.data is typed as TaskData
      console.log(event.operation.source.data.title);
    },
  });

  return <div>{source?.data.title}</div>;
}

Build docs developers (and LLMs) love