Skip to main content
The DragDropManager is the heart of dnd-kit. It coordinates all aspects of drag and drop operations, manages entities, handles collisions, and provides the API for controlling drag operations.

Overview

Every drag and drop context requires a manager instance. The manager:
  • Maintains a registry of draggable and droppable entities
  • Coordinates sensors for input handling
  • Manages the current drag operation state
  • Computes collisions between draggables and droppables
  • Applies modifiers to transform coordinates
  • Orchestrates plugins for extended functionality
  • Emits events for monitoring drag operations

Creating a manager

Basic usage

import {DragDropManager} from '@dnd-kit/dom';

const manager = new DragDropManager();
This creates a manager with the default preset:
  • Sensors: PointerSensor, KeyboardSensor
  • Plugins: Accessibility, AutoScroller, Cursor, Feedback, PreventSelection
  • Modifiers: None by default

Custom configuration

You can customize the manager by providing configuration options:
import {DragDropManager} from '@dnd-kit/dom';
import {PointerSensor} from '@dnd-kit/dom';
import {RestrictToVerticalAxis} from '@dnd-kit/abstract';

const manager = new DragDropManager({
  // Replace default sensors
  sensors: [PointerSensor],
  
  // Add modifiers
  modifiers: [RestrictToVerticalAxis],
  
  // Extend default plugins
  plugins: (defaults) => [...defaults, MyCustomPlugin],
});
Configuration options accept either a value (replaces defaults) or a function that receives defaults (allows extending).

Type signature

class DragDropManager<
  T extends Draggable,
  U extends Droppable
> {
  constructor(config?: DragDropManagerInput<DragDropManager>);
  
  // Core properties
  actions: DragActions<T, U>;
  registry: DragDropRegistry<T, U>;
  dragOperation: DragOperation<T, U>;
  monitor: DragDropMonitor<T, U>;
  collisionObserver: CollisionObserver<T, U>;
  renderer: Renderer;
  
  // Configuration
  sensors: Sensor[];
  plugins: Plugin[];
  modifiers: Modifier[];
  
  // Lifecycle
  destroy(): void;
}

Configuration options

Sensors

Sensors detect and handle user input:
type Customizable<T> = T | ((defaults: T) => T);

interface DragDropManagerInput {
  sensors?: Customizable<Sensors>;
}
Replace defaults:
const manager = new DragDropManager({
  sensors: [PointerSensor],
});
Extend defaults:
const manager = new DragDropManager({
  sensors: (defaults) => [...defaults, MyCustomSensor],
});

Plugins

Plugins extend functionality:
interface DragDropManagerInput {
  plugins?: Customizable<Plugins>;
}
Configure a plugin:
import {Feedback} from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    Feedback.configure({
      // Plugin-specific options
      duration: 300,
    }),
  ],
});

Modifiers

Modifiers transform drag coordinates:
interface DragDropManagerInput {
  modifiers?: Customizable<Modifiers>;
}
import {RestrictToVerticalAxis, SnapToGrid} from '@dnd-kit/abstract';

const manager = new DragDropManager({
  modifiers: [
    RestrictToVerticalAxis,
    SnapToGrid.configure({gridSize: 20}),
  ],
});

Renderer

The renderer handles visual updates:
interface DragDropManagerInput {
  renderer?: Renderer;
}

type Renderer = (callback: () => void) => void;
By default, the manager uses requestAnimationFrame. You can provide a custom renderer for framework integration:
// React example
const manager = new DragDropManager({
  renderer: (callback) => {
    flushSync(callback);
  },
});

Core properties

Actions

The actions property provides methods to control drag operations:
manager.actions.start({source, coordinates, event});
manager.actions.move({to, event});
manager.actions.stop({event, canceled});
See the DragDropManager API reference for details.

Registry

The registry manages all draggable and droppable entities:
// Access registered entities
const draggables = manager.registry.draggables; // EntityRegistry<Draggable>
const droppables = manager.registry.droppables; // EntityRegistry<Droppable>

// Get entity by ID
const draggable = manager.registry.draggables.get('item-1');

// Iterate entities
for (const draggable of manager.registry.draggables) {
  console.log(draggable.id);
}
Entities register themselves automatically when created with a manager.

Drag operation

The dragOperation property holds the current operation state:
const {dragOperation} = manager;

// Current status
dragOperation.status.idle      // boolean
dragOperation.status.dragging  // boolean
dragOperation.status.dropping  // boolean

// Entities involved
dragOperation.source           // Draggable | null
dragOperation.target           // Droppable | null

// Position and transform
dragOperation.position.current // {x: number, y: number}
dragOperation.position.initial // {x: number, y: number}
dragOperation.transform        // {x: number, y: number}

// Shape (bounding rectangle)
dragOperation.shape            // {current, initial, previous} | null

// Metadata
dragOperation.activatorEvent   // Event | null
dragOperation.canceled         // boolean
All properties are reactive and trigger effects when accessed inside effect contexts.

Monitor

The monitor emits events during drag operations:
manager.monitor.addEventListener('dragstart', (event) => {
  console.log('Drag started:', event.operation.source);
});

manager.monitor.addEventListener('dragmove', (event) => {
  console.log('Dragging:', event.operation.transform);
});

manager.monitor.addEventListener('dragend', (event) => {
  console.log('Drag ended:', event.operation.target);
});
See the DragDropManager API reference for available event types.

Collision observer

The collisionObserver computes and manages collisions:
// Get current collisions
const collisions = manager.collisionObserver.collisions;

// Force recomputation
manager.collisionObserver.forceUpdate();

// Compute with custom parameters
const customCollisions = manager.collisionObserver.computeCollisions(
  specificDroppables,
  customDetector
);
See Collision detection for details.

Customizable configuration

The Customizable<T> type allows flexible configuration:
type Customizable<T> = T | ((defaults: T) => T);

function resolveCustomizable<T>(
  value: Customizable<T> | undefined,
  defaults: T
): T;

As a value (replaces defaults)

const manager = new DragDropManager({
  plugins: [MyPlugin],  // Only MyPlugin, no defaults
});

As a function (receives defaults)

const manager = new DragDropManager({
  plugins: (defaults) => [...defaults, MyPlugin],  // Defaults + MyPlugin
});

Filtering defaults

const manager = new DragDropManager({
  plugins: (defaults) => defaults.filter(
    (plugin) => plugin !== UnwantedPlugin
  ),
});

DOM implementation

The @dnd-kit/dom package extends the abstract manager with DOM-specific features:
// From @dnd-kit/dom/src/core/manager/manager.ts
export class DragDropManager extends AbstractDragDropManager {
  constructor(input: Input = {}) {
    const plugins = resolveCustomizable(input.plugins, defaultPreset.plugins);
    const sensors = resolveCustomizable(input.sensors, defaultPreset.sensors);
    const modifiers = resolveCustomizable(input.modifiers, defaultPreset.modifiers);

    super({
      ...input,
      plugins: [ScrollListener, Scroller, StyleInjector, ...plugins],
      sensors,
      modifiers,
    });
  }
}
The DOM layer automatically injects required plugins:
  • ScrollListener: Tracks scroll position changes
  • Scroller: Manages scroll offsets during drag
  • StyleInjector: Injects required CSS styles
These internal plugins are always included before your custom plugins, ensuring core functionality works correctly.

Default preset

The default configuration provides sensible defaults:
// From @dnd-kit/dom/src/core/manager/manager.ts
export const defaultPreset = {
  modifiers: [],
  plugins: [
    Accessibility,      // Screen reader announcements
    AutoScroller,       // Scroll containers when near edges
    Cursor,             // Manage cursor styles
    Feedback,           // Visual drag feedback
    PreventSelection,   // Prevent text selection
  ],
  sensors: [
    PointerSensor,      // Mouse, touch, pen input
    KeyboardSensor,     // Keyboard navigation
  ],
};
You can reference this preset to build custom configurations:
import {defaultPreset} from '@dnd-kit/dom';

const manager = new DragDropManager({
  // Keep default sensors
  sensors: defaultPreset.sensors,
  
  // Customize plugins
  plugins: (defaults) => [
    ...defaults.filter(p => p !== AutoScroller),
    MyCustomPlugin,
  ],
});

Lifecycle management

Cleanup

Always clean up the manager when you’re done:
const manager = new DragDropManager();

// When finished
manager.destroy();
The destroy() method:
  • Stops any active drag operation
  • Unregisters all entities
  • Cleans up all sensors
  • Destroys all plugins and modifiers
  • Removes event listeners

Framework integration

Framework adapters handle lifecycle automatically:
// React example
function MyComponent() {
  const manager = useDragDropManager();
  // Automatically cleaned up when component unmounts
}

Type inference

The manager’s generic types flow through the entire system:
type InferDraggable<P> = P extends DragDropManager<infer T, any> ? T : never;
type InferDroppable<P> = P extends DragDropManager<any, infer T> ? T : never;

// Use in plugins
class MyPlugin<T extends DragDropManager<any, any>> extends Plugin<T> {
  constructor(manager: T) {
    super(manager);
    
    // Draggable and Droppable types are inferred from manager
    type Draggable = InferDraggable<T>;
    type Droppable = InferDroppable<T>;
  }
}

DragDropManager API

Complete API reference

Sensors

Input detection

Plugins

Extend functionality

Collision detection

Detect overlaps

Build docs developers (and LLMs) love