The JavaScript Drag & Drop library your grandparents warned you about.
—
The base Draggable class provides fundamental drag-and-drop functionality with container management, event handling, and plugin system. It serves as the foundation for all specialized draggable types.
Creates a new draggable instance with specified containers and options.
/**
* Creates a new draggable instance
* @param containers - Elements that contain draggable items
* @param options - Configuration options for drag behavior
*/
constructor(containers: DraggableContainer, options?: DraggableOptions);
type DraggableContainer = HTMLElement | HTMLElement[] | NodeList;Usage Example:
import { Draggable } from "@shopify/draggable";
// Single container
const draggable = new Draggable(document.querySelector('.container'), {
draggable: '.item',
delay: 150
});
// Multiple containers
const containers = document.querySelectorAll('.drag-container');
const multiContainer = new Draggable(containers, {
draggable: '.draggable-item'
});Methods for managing the draggable instance lifecycle.
/**
* Destroys the draggable instance and removes all event listeners
*/
destroy(): void;
/**
* Cancels the current drag operation immediately
*/
cancel(): void;
/**
* Returns true if currently dragging an element
*/
isDragging(): boolean;Methods for managing event listeners and triggering custom events.
/**
* Adds an event listener for drag events
* @param eventName - Name of the event to listen for
* @param callback - Function to call when event occurs
* @returns This draggable instance for chaining
*/
on<T extends TEventListType>(eventName: T, callback: (event: GetEventByEventName<T>) => void): this;
/**
* Removes an event listener
* @param eventName - Name of the event
* @param callback - Function to remove
* @returns This draggable instance for chaining
*/
off<T extends TEventListType>(eventName: T, callback: (event: GetEventByEventName<T>) => void): this;
/**
* Triggers a custom event
* @param event - Event instance to trigger
* @returns This draggable instance for chaining
*/
trigger(event: AbstractEvent): void;Usage Example:
const draggable = new Draggable(containers, options);
// Add event listeners
draggable.on('drag:start', (event) => {
console.log('Drag started:', event.source);
// Optionally cancel the drag
// event.cancel();
});
draggable.on('drag:move', (event) => {
console.log('Dragging over:', event.over);
});
// Remove event listener
const handleDragStop = (event) => {
console.log('Drag stopped');
};
draggable.on('drag:stop', handleDragStop);
draggable.off('drag:stop', handleDragStop);Methods for managing draggable containers after initialization.
/**
* Adds containers to the draggable instance
* @param containers - Container elements to add
* @returns This draggable instance for chaining
*/
addContainer(...containers: HTMLElement[]): this;
/**
* Removes containers from the draggable instance
* @param containers - Container elements to remove
* @returns This draggable instance for chaining
*/
removeContainer(...containers: HTMLElement[]): this;
/**
* Returns all draggable elements across all containers
*/
getDraggableElements(): HTMLElement[];
/**
* Returns draggable elements for a specific container
* @param container - Container to get elements from
*/
getDraggableElementsForContainer(container: HTMLElement): HTMLElement[];Methods for adding and removing plugins dynamically.
/**
* Adds plugins to the draggable instance
* @param plugins - Plugin classes to add
* @returns This draggable instance for chaining
*/
addPlugin(...plugins: (typeof AbstractPlugin)[]): this;
/**
* Removes plugins from the draggable instance
* @param plugins - Plugin classes to remove
* @returns This draggable instance for chaining
*/
removePlugin(...plugins: (typeof AbstractPlugin)[]): this;Methods for managing input sensors.
/**
* Adds sensors to the draggable instance
* @param sensors - Sensor classes to add
* @returns This draggable instance for chaining
*/
addSensor(...sensors: (typeof Sensor)[]): this;
/**
* Removes sensors from the draggable instance
* @param sensors - Sensor classes to remove
* @returns This draggable instance for chaining
*/
removeSensor(...sensors: (typeof Sensor)[]): this;Methods for working with CSS classes applied during drag operations.
/**
* Returns the first CSS class name for a class identifier
* @param name - Class identifier name
*/
getClassNameFor(name: DraggableClassNames): string;
/**
* Returns all CSS class names for a class identifier
* @param name - Class identifier name
*/
getClassNamesFor(name: DraggableClassNames): string[];Static properties available on the Draggable class.
class Draggable {
static Plugins: {
Announcement: typeof Announcement;
Focusable: typeof Focusable;
Mirror: typeof Mirror;
Scrollable: typeof Scrollable;
};
static Sensors: {
MouseSensor: typeof MouseSensor;
TouchSensor: typeof TouchSensor;
};
}interface DraggableOptions {
/** CSS selector for draggable elements within containers */
draggable?: string;
/** Minimum distance in pixels before drag starts */
distance?: number;
/** CSS selector, elements, or function defining drag handles */
handle?: string | NodeList | HTMLElement[] | HTMLElement | ((currentElement: HTMLElement) => HTMLElement);
/** Delay before drag starts (number or per-input delays) */
delay?: number | DelayOptions;
/** Timeout in milliseconds for removing placed classes after drop */
placedTimeout?: number;
/** Array of plugin classes to add */
plugins?: (typeof AbstractPlugin)[];
/** Array of sensor instances to use */
sensors?: Sensor[];
/** Plugins and sensors to exclude from defaults */
exclude?: {
plugins?: (typeof AbstractPlugin)[];
sensors?: (typeof Sensor)[];
};
/** CSS class names for different drag states */
classes?: {[key in DraggableClassNames]: string | string[]};
/** Accessibility announcement options */
announcements?: AnnouncementOptions;
/** Collidable elements for collision detection */
collidables?: Collidables;
/** Mirror plugin options */
mirror?: MirrorOptions;
/** Scrollable plugin options */
scrollable?: ScrollableOptions;
/** Swap animation options */
swapAnimation?: SwapAnimationOptions;
/** Sort animation options */
sortAnimation?: SortAnimationOptions;
}
interface DelayOptions {
mouse?: number;
drag?: number;
touch?: number;
}
type DraggableClassNames =
| 'body:dragging'
| 'container:dragging'
| 'source:dragging'
| 'source:placed'
| 'container:placed'
| 'draggable:over'
| 'container:over'
| 'source:original'
| 'mirror';Usage Example:
const draggable = new Draggable(containers, {
draggable: '.drag-item',
handle: '.drag-handle',
delay: { mouse: 100, touch: 150 },
distance: 10,
placedTimeout: 1000,
exclude: {
sensors: [TouchSensor], // Exclude touch sensor on desktop
plugins: [Announcement] // Exclude announcement plugin
},
classes: {
'source:dragging': 'my-dragging-class',
'body:dragging': 'drag-in-progress'
},
mirror: {
constrainDimensions: true,
xAxis: true,
yAxis: true
},
scrollable: {
speed: 15,
sensitivity: 50
}
});Install with Tessl CLI
npx tessl i tessl/npm-shopify--draggable