dragula
A vanilla JavaScript drag-and-drop library that figures out sort order on its own, with no framework required.
Repository Health
Technical Analysis
Dragula is a vanilla JavaScript library, created by Nicolas Bevacqua in 2015, that makes drag-and-drop between DOM containers close to a one-line integration: pass it a list of container elements and it wires up mouse/touch events, renders a floating mirror of the dragged item, and figures out the correct sort position by comparing the cursor against sibling bounding rectangles.
It ships with no required framework — options like moves, accepts, invalid, and copy give fine-grained control over what can be dragged and where it can land, and official Angular and React bridge packages exist for teams that want a component wrapper. The library has been effectively feature-complete and in low-maintenance mode since 2020 (last tagged release 3.7.3), but remains widely used and forms the vanilla-JS core behind several drag-and-drop wrapper libraries.
What You Get
- A single
dragula(containers, options)factory that returns an event-emittingdrakeAPI (start,end,cancel,remove,destroy,canMove). - Automatic mirror-element rendering and CSS classes (
gu-mirror,gu-transit,gu-hide,gu-unselectable) to style drag feedback. - Ten drake events (
drag,dragend,drop,cancel,remove,shadow,over,out,cloned) for hooking persistence or animation into any stage of a drag. - Prebuilt UMD, minified, and CSS builds in
dist/for use without a bundler, plus official Angular and React bridge packages.
Common Use Cases
- Kanban/task-board column reordering.
- Sortable admin list or table rows.
- Drag-to-copy asset or file organizers.
- Cross-container playlist or queue builders.
Under The Hood
Architecture
Dragula centers on a single factory function, dragula(containers, options) (dragula.js), that returns a drake object built with the contra/emitter mixin — an event emitter rather than a class instance. All drag state (the dragged item, its source container, the floating mirror element, offsets, and the current/initial sibling) lives in closure-scoped variables rather than object fields, and every DOM listener (mousedown/mouseup/mousemove and their touch/pointer equivalents via the internal touchy helper) is delegated from document.documentElement instead of bound per draggable element. The tiny classes.js module is the only other file in the runtime bundle, providing a self-contained regex-based class add/remove helper for toggling gu-transit/gu-mirror/gu-hide/gu-unselectable. There’s no dependency injection or plugin registry; extension points are limited to the moves/accepts/invalid/copy option callbacks, so changing core drag-detection logic means editing the one large closure directly.
Tech Stack
Written in plain ES5-style JavaScript with 'use strict' and no TypeScript, depending only on contra (event emitter) and crossvent (cross-browser event binding), both maintained by the same author. The build pipeline uses Browserify to produce a UMD bundle (dist/dragula.js), uglify-js for minification, Stylus to compile dragula.styl into dist/dragula.css, and jshint (not ESLint) for linting per .jshintrc. Tests run via tape bundled through Browserify and executed in a real browser via tape-run; watchify drives the dev rebuild loop. Distribution targets the browser directly — no server or database component — via npm and a CDN build for script-tag use.
Code Quality
The test/ directory has focused suites for drag, drop, cancel, remove, destroy, containers, defaults, and the public API, each exercising drake events against a real DOM via tape-run, which is a reasonably thorough behavioral net for a UI interaction library. There are no type annotations or .d.ts files, and error handling is implicit — most internal functions guard with early returns (e.g., if (!drake.dragging) return;) rather than throwing, which fits a UI library where failures should silently no-op. Naming is terse and consistent (underscore-prefixed closure variables like _item, _mirror, _source), matching typical 2015-era vanilla-JS conventions, and linting is enforced via jshint rather than a modern linter. The repository has had no commits since mid-2024 and no recent CI activity.
API Design
The public surface is deliberately minimal: call dragula(containers, options) and get back a drake with start/end/cancel/remove/destroy/canMove methods and ten emitted events (drag, dragend, drop, cancel, remove, shadow, over, out, cloned). Getting started requires no markup conventions or wrapper components — any DOM elements can be containers — and the four CSS classes needed for styling are documented directly in the README. Official Angular and React bridge packages exist for teams wanting idiomatic framework components instead of the raw vanilla API, lowering onboarding friction further for those ecosystems.
Used by 2 apps in this directory
Fleetbase
Logistics
Modular open-source logistics and supply chain operating system
OpenProject
Project Management · Productivity · Collaboration
The open source project management platform that unifies Gantt charts, agile boards, time tracking, and team collaboration under full self-hosted control.