Skip to main content
Droppable represents an entity that can receive draggable items in a drag and drop operation. It extends the base Entity class with droppable-specific functionality including type-based acceptance rules, collision detection, and drop target status tracking.

Constructor

Creates a new droppable entity.
const droppable = new Droppable<T, U>(input, manager);
input
DroppableInput<T>
required
Configuration object for the droppable.
manager
U | undefined
required
The drag and drop manager instance, or undefined for unmanaged entities.
T
extends Data
default:"Data"
Type parameter for the data associated with this droppable.
U
extends DragDropManager<any, any>
default:"DragDropManager<any, any>"
Type parameter for the manager type.

Properties

Inherited from Entity

id
UniqueIdentifier
The unique identifier of the entity. Can be updated dynamically.
droppable.id = 'new-zone-id';
data
T
The data associated with the entity.
droppable.data = {label: 'Updated label', capacity: 20};
manager
U | undefined
The drag and drop manager instance.
droppable.manager = newManager;
disabled
boolean
Whether the entity is disabled.
droppable.disabled = true;

Droppable-Specific

accept
Type | Type[] | ((draggable: Draggable) => boolean) | undefined
Types of draggables that can be dropped here, or a function to determine compatibility.
// Accept only 'card' type
droppable.accept = 'card';

// Accept multiple types
droppable.accept = ['card', 'widget'];

// Custom logic
droppable.accept = (draggable) => draggable.data.size <= 10;
type
Type | undefined
The type/category of the droppable entity.
droppable.type = 'container';
collisionDetector
CollisionDetector
The collision detector for this droppable.
droppable.collisionDetector = closestCenter;
collisionPriority
CollisionPriority | number | undefined
The collision priority for this droppable.
droppable.collisionPriority = CollisionPriority.Highest;
shape
Shape | undefined
The current shape of this droppable. Typically set automatically based on DOM measurements.
droppable.shape = new Rectangle({
  x: 0,
  y: 0,
  width: 200,
  height: 100
});

Computed Properties

isDropTarget

isDropTarget
boolean
Checks if this droppable is the current drop target.
if (droppable.isDropTarget) {
  console.log('Draggable is over this zone');
}
Returns true if this droppable’s ID matches the current drag operation’s target ID.

Methods

accepts()

Checks whether this droppable accepts a given draggable.
const canDrop = droppable.accepts(draggable);
draggable
Draggable
required
The draggable to check compatibility for.
return
boolean
true if the draggable can be dropped here, false otherwise.
Logic:
  1. If accept is undefined, returns true (accepts all)
  2. If accept is a function, calls it with the draggable
  3. If draggable has no type, returns false
  4. If accept is an array, checks if it includes the draggable’s type
  5. If accept is a single type, checks for exact match

Inherited from Entity

register()

Registers the entity with its manager.
const cleanup = droppable.register();
return
CleanupFunction | void
A cleanup function to unregister the entity, or void if no manager is set.

unregister()

Unregisters the entity from its manager.
droppable.unregister();

destroy()

Cleans up the entity when it’s no longer needed.
droppable.destroy();

Usage Examples

Basic Droppable

import {Droppable, DragDropManager} from '@dnd-kit/abstract';
import {rectangleIntersection} from '@dnd-kit/collision';

const manager = new DragDropManager();

const droppable = new Droppable(
  {
    id: 'zone-1',
    collisionDetector: rectangleIntersection,
    data: {label: 'Drop here'}
  },
  manager
);

With Type Acceptance

// Accept only 'card' type draggables
const droppable = new Droppable(
  {
    id: 'card-zone',
    accept: 'card',
    collisionDetector: rectangleIntersection
  },
  manager
);

// Accept multiple types
const multiDroppable = new Droppable(
  {
    id: 'multi-zone',
    accept: ['card', 'widget', 'item'],
    collisionDetector: rectangleIntersection
  },
  manager
);

With Custom Acceptance Logic

const droppable = new Droppable(
  {
    id: 'smart-zone',
    accept: (draggable) => {
      // Only accept if priority is high
      if (draggable.data.priority !== 'high') {
        return false;
      }
      
      // Check capacity
      const currentItems = droppable.data.items?.length ?? 0;
      return currentItems < droppable.data.capacity;
    },
    collisionDetector: rectangleIntersection,
    data: {capacity: 5, items: []}
  },
  manager
);

With Collision Priority

import {CollisionPriority} from '@dnd-kit/abstract';

const highPriorityZone = new Droppable(
  {
    id: 'priority-zone',
    collisionPriority: CollisionPriority.Highest,
    collisionDetector: rectangleIntersection
  },
  manager
);

// Custom numeric priority
const customPriorityZone = new Droppable(
  {
    id: 'custom-zone',
    collisionPriority: 999,
    collisionDetector: rectangleIntersection
  },
  manager
);

Checking Acceptance

const droppable = new Droppable(
  {
    id: 'zone-1',
    accept: 'card',
    collisionDetector: rectangleIntersection
  },
  manager
);

const cardDraggable = new Draggable({id: 'item-1', type: 'card'}, manager);
const widgetDraggable = new Draggable({id: 'item-2', type: 'widget'}, manager);

console.log(droppable.accepts(cardDraggable));   // true
console.log(droppable.accepts(widgetDraggable)); // false

Checking Drop Target Status

const droppable = new Droppable(
  {
    id: 'zone-1',
    collisionDetector: rectangleIntersection
  },
  manager
);

// During a drag operation
if (droppable.isDropTarget) {
  console.log('A draggable is hovering over this zone');
  // Update UI, show highlight, etc.
}

Dynamic Updates

const droppable = new Droppable(
  {
    id: 'zone-1',
    accept: 'card',
    collisionDetector: rectangleIntersection
  },
  manager
);

// Change accepted types
droppable.accept = ['card', 'widget'];

// Disable temporarily
droppable.disabled = true;

// Update collision priority
droppable.collisionPriority = CollisionPriority.High;

// Update data
droppable.data = {
  ...droppable.data,
  capacity: 20
};

TypeScript Types

interface DropZoneData {
  label: string;
  category: string;
  capacity: number;
  items: string[];
}

const droppable = new Droppable<DropZoneData>(
  {
    id: 'zone-1',
    collisionDetector: rectangleIntersection,
    data: {
      label: 'Todo',
      category: 'tasks',
      capacity: 10,
      items: []
    }
  },
  manager
);

// TypeScript knows the shape of data
const capacity = droppable.data.capacity; // number
const items = droppable.data.items;       // string[]

With Custom Collision Detector

import type {CollisionDetector} from '@dnd-kit/abstract';

const customCollisionDetector: CollisionDetector = ({droppable, dragOperation}) => {
  const {source} = dragOperation;
  if (!source?.shape || !droppable.shape) return null;

  // Custom collision logic
  const overlap = calculateOverlap(source.shape, droppable.shape);
  
  if (overlap > 0) {
    return {
      id: droppable.id,
      type: CollisionType.ShapeIntersection,
      priority: CollisionPriority.Normal,
      value: overlap,
      data: {overlap}
    };
  }

  return null;
};

const droppable = new Droppable(
  {
    id: 'zone-1',
    collisionDetector: customCollisionDetector
  },
  manager
);

Monitoring Drop Events

const droppable = new Droppable(
  {
    id: 'zone-1',
    collisionDetector: rectangleIntersection,
    data: {items: []}
  },
  manager
);

manager.monitor.addEventListener('dragend', (event) => {
  if (event.operation.target?.id === droppable.id) {
    const draggedItem = event.operation.source;
    console.log(`Item ${draggedItem?.id} was dropped on zone ${droppable.id}`);
    
    // Update data
    droppable.data.items.push(draggedItem?.id);
  }
});

Nested Droppables

// Parent container with low priority
const parentZone = new Droppable(
  {
    id: 'parent',
    collisionPriority: CollisionPriority.Low,
    collisionDetector: rectangleIntersection
  },
  manager
);

// Child zone with higher priority
const childZone = new Droppable(
  {
    id: 'child',
    collisionPriority: CollisionPriority.High,
    collisionDetector: rectangleIntersection
  },
  manager
);

// Child will be preferred when both overlap

CollisionPriority Enum

enum CollisionPriority {
  Lowest = 0,
  Low = 1,
  Normal = 2,
  High = 3,
  Highest = 4,
}
Higher priority droppables take precedence when multiple collisions are detected.

See Also

Build docs developers (and LLMs) love