Droppable
The Droppable class defines a drop target where draggable elements can be dropped. Each droppable must be associated with a DOM element.
Note that Droppable does not do anything by itself. You have to add it to a DndObserver instance and match it with some Draggable instances. The DndObserver will then emit events when the draggable enters, leaves, or collides with the droppable.
Example
import { Droppable } from 'dragdoll/droppable';
const dropZone = document.querySelector('.drop-zone') as HTMLElement;
const droppable = new Droppable(dropZone, {
accept: new Set(['groupA']),
data: { info: 'Custom drop zone info' },
});
// Listen to the destroy event to perform cleanup
droppable.on('destroy', () => {
console.log('Droppable destroyed');
});
// Later, when you want to remove the droppable
droppable.destroy();Class
class Droppable {
constructor(element: HTMLElement | SVGSVGElement | null, options: DroppableOptions = {}) {}
}Constructor Parameters
- element
- The target DOM element that represents the drop zone. Can be
nullif you want to set it later or use a customcomputeClientRectfunction.
- The target DOM element that represents the drop zone. Can be
- options
- An optional options object following the
DroppableOptionsinterface. - Check out the Options section for more information.
- Default:
{}.
- An optional options object following the
Options
Here you can find more information about the options you can provide to the constructor. The typings here follow the DroppableOptions interface.
id
type id = DroppableId;The id is a unique identifier for the droppable that is assigned as the droppable's id property. It can only be provided once via the constructor options and should not be changed after instantiation. Reason being that the DndObserver will use the id to store data related to the droppable.
Default is a unique symbol.
accept
type accept = Set<DraggableDndGroup> | ((draggable: AnyDraggable) => boolean);Check out the accept property docs for more information.
data
type data = { [key: string]: any };Check out the data property docs for more information.
computeClientRect
type computeClientRect = (droppable: Droppable) => Rect;A function that should return the current bounding client rectangle of the droppable. This rectangle is used for collision detection.
The returned rectangle should have the following properties:
x: The x-coordinate of the rectangle's left edgey: The y-coordinate of the rectangle's top edgewidth: The width of the rectangleheight: The height of the rectangle
When to customize: You might want to customize this function when:
- The droppable's
elementisnulland you need to provide a custom rectangle - You want to use a custom bounding area (e.g., smaller or larger than the actual element)
- You're implementing custom collision detection logic
- You need to account for transforms or scaling that affect the visual bounds
Example:
const droppable = new Droppable(null, {
computeClientRect: (droppable) => {
// Return a custom rectangle when element is null
return { x: 100, y: 100, width: 200, height: 200 };
},
});
// Or use a custom rectangle even when element exists
const droppable = new Droppable(element, {
computeClientRect: (droppable) => {
const rect = droppable.element?.getBoundingClientRect();
if (!rect) return droppable.getClientRect();
// Return a slightly larger rectangle for easier dropping
return {
x: rect.x - 10,
y: rect.y - 10,
width: rect.width + 20,
height: rect.height + 20,
};
},
});Default behavior: By default, this returns element.getBoundingClientRect() if element is not null, otherwise returns the cached client rect from getClientRect().
Properties
id
type id = DroppableId;The unique identifier for this droppable. Default is a unique symbol. Read-only.
element
type element = HTMLElement | SVGSVGElement | null;The associated DOM element whose bounding client rectangle is used for collision detection. Can be null if you're using a custom computeClientRect function. Read-only.
accept
type accept = Set<DraggableDndGroup> | ((draggable: AnyDraggable) => boolean);Controls which draggables can collide with this droppable when used in a DndObserver.
- Set mode: accepts a draggable when its
dndGroupsset contains any of the identifiers in this set. - Function mode: called during collision detection for every candidate. Return
trueto accept,falseto reject. You can incorporate the draggable'sdndGroupshere or come up with any other acceptance criteria.
Default is () => true (accepts all draggables).
data
type data = { [key: string]: any };Custom data associated with this droppable. This data is persisted until manually overridden. You can directly modify the object at any time.
computeClientRect
type computeClientRect = (droppable: Droppable) => Rect;A function that should return the current bounding client rectangle of the droppable. This rectangle is used for collision detection. Check out the computeClientRect option docs for more information.
isDestroyed
type isDestroyed = boolean;Boolean flag indicating whether this instance has been destroyed. Read-only.
Methods
on
type on = <T extends keyof DroppableEventCallbacks>(
type: T,
listener: DroppableEventCallbacks[T],
listenerId?: SensorEventListenerId,
) => SensorEventListenerId;Adds a listener to a droppable event. Returns a listener id, which can be used to remove this specific listener. By default this will always be a symbol unless manually provided.
Please check the Events section for more information about the events and their payloads.
Example
droppable.on('destroy', (e) => {
console.log('destroy', e);
});off
type off = <T extends keyof DroppableEventCallbacks>(
type: T,
listenerId: SensorEventListenerId,
) => void;Removes a listener (based on listener id) from a droppable event.
Example
const id = droppable.on('destroy', () => console.log('destroy'));
droppable.off('destroy', id);getClientRect
type getClientRect = () => Readonly<Rect>;Returns the cached bounding client rectangle of the droppable as a read-only object. This rect is updated when updateClientRect() is called (e.g., by DndObserver at drag start or on scroll).
Example
const rect = droppable.getClientRect();
console.log(rect.x, rect.y, rect.width, rect.height);updateClientRect
type updateClientRect = () => void;Updates the cached client rectangle by calling the computeClientRect function. This is typically called automatically by DndObserver at drag start or on scroll, but can be manually triggered if needed.
Example
// Update the cached client rectangle.
droppable.updateClientRect();destroy
type destroy = () => void;Destroys the droppable instance:
- Emits the
destroyevent (if any listeners are registered). - Marks the droppable as destroyed to prevent further operations.
Example
droppable.destroy();Events
destroy
Emitted when the droppable is destroyed. There is no payload for this event.
Types
DroppableId
// Import
import type { DroppableId } from 'dragdoll/droppable';
// Type
type DroppableId = symbol | string | number;DroppableEventType
// Import
import type { DroppableEventType } from 'dragdoll/droppable';
// Type
type DroppableEventType = 'destroy';DroppableEventCallbacks
// Import
import type { DroppableEventCallbacks } from 'dragdoll/droppable';
// Interface
interface DroppableEventCallbacks {
destroy: () => void;
}DroppableOptions
// Import
import type { DroppableOptions } from 'dragdoll/droppable';
// Interface
interface DroppableOptions {
id?: DroppableId;
accept?: Set<DraggableDndGroup> | ((draggable: AnyDraggable) => boolean);
data?: { [key: string]: any };
computeClientRect?: (droppable: Droppable) => Rect;
}DroppableDefaultSettings
// Import
import { DroppableDefaultSettings } from 'dragdoll/droppable';
// Object
const DroppableDefaultSettings = {
accept: () => true,
computeClientRect: (droppable: Droppable) =>
droppable.element?.getBoundingClientRect() || droppable.getClientRect(),
};The default settings object used by Droppable when options are not provided.