CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-shopify--draggable

The JavaScript Drag & Drop library your grandparents warned you about.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Shopify Draggable

Shopify Draggable is a comprehensive JavaScript drag-and-drop library built with TypeScript that offers complete control over drag-and-drop behavior through a flexible API. It abstracts native browser events (drag, mouse, touch, and force touch) into a unified interface and includes specialized modules: Sortable for reordering elements, Droppable for defining drop zones, and Swappable for element swapping.

Package Information

  • Package Name: @shopify/draggable
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @shopify/draggable

Core Imports

import { Draggable, Sortable, Droppable, Swappable } from "@shopify/draggable";

Base classes and utilities:

import { BaseEvent, BasePlugin, Sensors, Plugins } from "@shopify/draggable";

For CommonJS:

const { Draggable, Sortable, Droppable, Swappable } = require("@shopify/draggable");
const { BaseEvent, BasePlugin, Sensors, Plugins } = require("@shopify/draggable");

ES modules (alternative imports):

import Draggable from "@shopify/draggable/lib/draggable";
import Sortable from "@shopify/draggable/lib/sortable";

Basic Usage

import { Draggable } from "@shopify/draggable";

// Basic draggable setup
const draggable = new Draggable(document.querySelectorAll('.container'), {
  draggable: '.item'
});

// Listen to drag events
draggable.on('drag:start', (event) => {
  console.log('Started dragging:', event.source);
});

draggable.on('drag:stop', (event) => {
  console.log('Stopped dragging:', event.source);
});

// Cleanup when done
draggable.destroy();

Architecture

Shopify Draggable is built around several key components:

  • Core Draggable: Base class providing fundamental drag-and-drop functionality
  • Specialized Classes: Sortable, Droppable, and Swappable extend Draggable for specific use cases
  • Event System: Comprehensive event lifecycle with cancelable events and custom data
  • Sensor System: Pluggable input handling for mouse, touch, and native drag events
  • Plugin Architecture: Extensible system with built-in plugins for mirrors, scrolling, announcements, etc.
  • Type Safety: Full TypeScript integration with generic event types and comprehensive interfaces

Capabilities

Core Draggable

Basic drag-and-drop functionality with container management, event handling, and plugin system. Provides the foundation for all other draggable types.

class Draggable<TEventListType = DraggableEventNames> {
  constructor(containers: DraggableContainer, options?: DraggableOptions);
  destroy(): void;
  on<T extends TEventListType>(eventName: T, callback: (event: GetEventByEventName<T>) => void): this;
  off<T extends TEventListType>(eventName: T, callback: (event: GetEventByEventName<T>) => void): this;
  trigger(event: AbstractEvent): void;
  isDragging(): boolean;
}

type DraggableContainer = HTMLElement | HTMLElement[] | NodeList;

Core Draggable

Sortable Lists

Reorder elements within or between containers with automatic position tracking and smooth animations. Perfect for to-do lists, priority queues, and dashboard widgets.

class Sortable<T = SortableEventNames> extends Draggable<T> {
  constructor(containers: DraggableContainer, options?: DraggableOptions);
  index(element: HTMLElement): number;
  getSortableElementsForContainer(container: HTMLElement): HTMLElement[];
}

Sortable Lists

Droppable Zones

Create designated drop zones where draggable elements can be placed. Includes visual feedback and validation for valid/invalid drop targets.

class Droppable<T = DroppableEventNames> extends Draggable<T> {
  constructor(containers: DraggableContainer, options: DroppableOptions);
  getClassNameFor(name: DroppableClassNames): string;
}

interface DroppableOptions extends DraggableOptions {
  dropzone: string | NodeList | HTMLElement[] | (() => NodeList | HTMLElement[]);
  classes?: {[key in DroppableClassNames]: string};
}

Droppable Zones

Swappable Elements

Enable element swapping where dragging over another element exchanges their positions. Order-independent interaction for grid layouts and card arrangements.

class Swappable<T = SwappableEventNames> extends Draggable<T> {
  constructor(containers: DraggableContainer, options?: DraggableOptions);
}

Swappable Elements

Event System

Comprehensive event lifecycle with drag events, specialized events for each draggable type, and plugin-specific events. All events extend AbstractEvent with cancellation support.

abstract class AbstractEvent<TData = {[key: string]: any}> {
  readonly type: string;
  readonly cancelable: boolean;
  constructor(data: TData);
  cancel(): void;
  canceled(): boolean;
  clone(data?: Partial<TData>): AbstractEvent<TData>;
}

export {AbstractEvent as BaseEvent};

Events

Sensors

Input detection system supporting mouse, touch, native drag events, and force touch. Pluggable architecture allows custom sensor implementation for specialized input handling.

class Sensor {
  constructor(containers: HTMLElement | HTMLElement[] | NodeList, options?: SensorOptions);
  attach(): this;
  detach(): this;
  addContainer(...containers: HTMLElement[]): void;
  removeContainer(...containers: HTMLElement[]): void;
  trigger(element: HTMLElement, sensorEvent: SensorEvent): SensorEvent;
}

Sensors

Plugins

Extensible plugin system with built-in plugins for mirror elements, auto-scrolling, accessibility announcements, focus management, collision detection, and animations.

abstract class AbstractPlugin {
  constructor(draggable: Draggable);
  protected abstract attach(): void;
  protected abstract detach(): void;
}

export {AbstractPlugin as BasePlugin};

Plugins

Types

interface DraggableOptions {
  draggable?: string;
  distance?: number;
  handle?: string | NodeList | HTMLElement[] | HTMLElement | ((currentElement: HTMLElement) => HTMLElement);
  delay?: number | DelayOptions;
  placedTimeout?: number;
  plugins?: (typeof AbstractPlugin)[];
  sensors?: Sensor[];
  exclude?: {
    plugins?: (typeof AbstractPlugin)[];
    sensors?: (typeof Sensor)[];
  };
  classes?: {[key in DraggableClassNames]: string | string[]};
  announcements?: AnnouncementOptions;
  collidables?: Collidables;
  mirror?: MirrorOptions;
  scrollable?: ScrollableOptions;
  swapAnimation?: SwapAnimationOptions;
  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';

docs

core-draggable.md

droppable.md

events.md

index.md

plugins.md

sensors.md

sortable.md

swappable.md

tile.json