| Author: | Shopify |
|---|---|
| Views Total: | 8,910 views |
| Official Page: | Go to website |
| Last Update: | October 22, 2025 |
| License: | MIT |
Preview:

Description:
draggable.js is a customizable draggable/droppable/sortable/swappable JavaScript library that works with mouse drag, touch, and force touch events.
How to use it:
Install it via package managers:
# Yarn $ yarn add @shopify/draggable # NPM $ npm install @shopify/draggable --save
Import a module of your choice into the project.
// core modules
import { Draggable, Droppable, Sortable, Swappable } from '@shopify/draggable';
// plugins
import { Plugins } from '@shopify/draggable';
// or
import Collidable from '@shopify/draggable/lib/plugins/collidable';
import ResizeMirror from '@shopify/draggable/lib/plugins/resize-mirror';
import Snappable from '@shopify/draggable/lib/plugins/snappable';
import SwapAnimation from '@shopify/draggable/lib/plugins/swap-animation';
import SortAnimation from '@shopify/draggable/lib/plugins/sort-animation';Or directly load JavaScript libraries into your document.
<!-- Entire bundle --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/draggable.bundle.js"></script> <!-- legacy bundle for older browsers (IE11) --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/draggable.bundle.legacy.js"></script> <!-- Draggable only --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/draggable.js"></script> <!-- Sortable only --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/sortable.js"></script> <!-- Droppable only --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/droppable.js"></script> <!-- Swappable only --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/swappable.js"></script> <!-- Plugins only --> <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/lib/plugins.js"></script>
Draggable API, options, and events.
// containers: specify the containers that hold draggable items // options: an array of options as shown below new Draggable(containers, options) // eventName: event name as shown below // listener: callback for events draggable.on(eventName, listener) // eventName: event name as shown below // listener: callback for events draggable.off(eventName, listener) // eventName: event name as shown below draggable.trigger(eventName, event) // destroy draggable.destroy() // add plugins draggable.addPlugin(plugins); // remove plugins draggable.removePlugin(plugins); // add sensors draggable.addSensor(sensors); // remove sensors draggable.removeSensor(sensors); // add containers draggable.addContainer(containers); // remove containers draggable.removeContainer(containers); // return class name for class identifier draggable.getClassNameFor(name); // check if is dragging draggable.isDragging(); // return draggable elements for given container, excluding potential mirror or original source. draggable.getDraggableElementsForContainer(container);
// options
draggable: '.draggable-source',
handle: null, // css selector for a handle element
delay: 0,
distance: 0, // the distance you want the pointer to have moved before drag starts
sensors: [], // how drag operations get triggered, by listening to native browser events: DragSensor, ForceTouchSensor, MouseSensor, TouchSensor
plugins: [Announcement, Focusable, Mirror, Scrollable],
classes: {
'container:dragging': 'draggable-container--is-dragging',
'source:dragging': 'draggable-source--is-dragging',
'source:placed': 'draggable-source--placed',
'container:placed': 'draggable-container--placed',
'body:dragging': 'draggable--is-dragging',
'draggable:over': 'draggable--over',
'container:over': 'draggable-container--over',
'mirror': 'draggable-mirror',
},// events
draggable.on('drag:start', function(){
// ...
})
draggable.on('drag:move', function(){
// ...
})
draggable.on('drag:over', function(){
// ...
})
draggable.on('drag:over:container', function(){
// ...
})
draggable.on('drag:out', function(){
// ...
})
draggable.on('drag:out:container', function(){
// ...
})
draggable.on('drag:stop', function(){
// ...
})
draggable.on('drag:pressure', function(){
// ...
})
draggable.on('draggable:initialize', function(){
// ...
})
draggable.on('draggable:destroy', function(){
// ...
})Sortable API, options, and events.
// Check out Draggable API for the base API // options: an array of options as shown below new Sortable(containers, options) ...
// Check out Draggable API for the base API
// events
Sortable.on('sortable:start', function(){
// ...
})
Sortable.on('sortable:sort', function(){
// ...
})
Sortable.on('sortable:sorted', function(){
// ...
})
Sortable.on('sortable:stop', function(){
// ...
})Swappable API, options, and events.
// Check out Draggable API for the base API
// containers: specify the containers that hold Swappable items
// options: an array of options as shown below
new Swappable(containers, options)
Swappable.on('swappable:start', function(){
// ...
})
Swappable.on('swappable:swap', function(){
// ...
})
Swappable.on('swappable:swapped', function(){
// ...
})
Swappable.on('swappable:stop', function(){
// ...
})Droppable API, options, and events.
// Check out Draggable API for the base API // options: an array of options as shown below new Droppable(containers, options) ...
// Check out Draggable events for the base events
droppable.on('droppable:dropped', function(){
// ...
})
droppable.on('droppable:returned', function(){
// ...
})Plugins API.
// Collidable Plugin Events
sortable.on('collidable:in', () => console.log('collidable:in'));
sortable.on('collidable:out', () => console.log('collidable:out'));
// Snappable Plugin Events
sortable.on('snap:in', () => console.log('snap:in'));
sortable.on('snap:out', () => console.log('snap:out'));
// SwapAnimation Plugin Options
const sortable = new Sortable(document.querySelectorAll('ul'), {
draggable: 'li',
swapAnimation: {
duration: 200,
easingFunction: 'ease-in-out',
horizontal: true
},
plugins: [Plugins.SwapAnimation]
});
// SortAnimation Plugin Options
const sortable = new Sortable(document.querySelectorAll('ul'), {
draggable: 'li',
sortAnimation: {
duration: 200,
easingFunction: 'ease-in-out',
},
plugins: [Plugins.SortAnimation]
});Changelog:
v1.2.1 (10/22/2025)
- Update
v1.1.4 (03/18/2025)
- Add provenance statement
v1.1.3 (10/13/2023)
- Adds AutoBind decorator
- Fixes VSCode search to exclude generated files/folders
- Converts ResizeMirror test to typescript
v1.1.2 (10/12/2023)
- Update
v1.1.1 (09/28/2023)
- Also resolves absolute paths for ts build declarations
- Renames build files with .cjs and .mjs
v1.1.0 (09/26/2023)
- Update
v1.0.0statble (09/23/2023)
- Update
v1.0.0-beta11 (07/15/2020)
- Added exclude option to allow disable default plugins and sensors
- Added missing plugin types
- Support set the type of callback function according to the event type
- Fixes drag start concurrency (delay and distance options)
- Fixes text in mirror blurry
- Fixes accidently append mirror
v1.0.0-beta10 (06/19/2020)
- Added SortAnimation plugin
- Added distance?: number to DraggableOptions TS interface
- Fix mirror dimensions when constrainDimensions is active and not using fixed item width
v1.0.0-beta9 (08/27/2019)
- Added distance option
- Added thresholdX and thresholdY mirror options
- Fixes preventing of contextmenu in MouseSensor
- Fixes SortableEvent over and overContainer giving incorrect properties
v1.0.0-beta8 (09/08/2018)
- Announcement plugin to use textContent instead of innerHTML
v1.0.0-beta7 (06/10/2018)
- Added ResizeMirror plugin
- Fixed native drag events with draggable
- Fixed mouse position bug in scrollable
- Fix initial drag move event






