Skip to content

What is @anil-labs/dnd? ​

A drag-and-drop engine for sortable lists, built from scratch on Pointer Events, with first-class bindings for every major framework.

The project is a small family of packages sharing one engine:

PackageWhat it gives you
@anil-labs/dnd-coreThe zero-dependency engine: createSortable() for vanilla DOM, plus the DndList controller and adapter contract the bindings are built on.
@anil-labs/dnd-react<Draggable> component and useDraggable() hook.
@anil-labs/dnd<Draggable> component (v-model) and useDraggable() composable.
@anil-labs/dnd-svelteThe use:draggable action.
@anil-labs/dnd-solidThe createDraggable() primitive.
@anil-labs/dnd-elementThe <dnd-list> Web Component any framework or plain HTML.

Feature highlights ​

  • Sorting & cross-list groups drag within a list or between lists sharing a group; control transfers with pull/put booleans, allow-lists or functions.
  • Clone mode palette → canvas flows with pull: 'clone' and an optional clone(item) transform.
  • Multi-drag Ctrl/Cmd-click to select several items and drag them as one batch, with a count badge on the ghost.
  • Swap mode exchange positions instead of inserting; ideal for grid dashboards.
  • Keyboard & ARIA Space to grab, arrows to move, aria-live announcements; fully usable without a pointer.
  • FLIP animation reorder transitions via the Web Animations API, honoring prefers-reduced-motion.
  • Handles, filters, touch delay start drags only from a grip, block interactive children, long-press on touch.
  • Autoscroll window and nested scroll containers scroll when you drag near an edge.
  • Custom ghosts render any element as the floating drag preview.
  • Spill behaviour revert or remove items dropped outside every list.

The data model ​

The engine never mutates your arrays. You own the state; the engine hit-tests the DOM and asks your binding to apply primitive changes (move, insert, remove). Each binding translates those into idiomatic updates a v-model emit in Vue, a setState in React, a reassignment in Svelte, a signal write in Solid. In vanilla mode the DOM itself is the state and the engine reorders children in place.

That architecture is why one engine drives every framework identically: the gesture logic, group rules, keyboard interaction and animation all live in @anil-labs/dnd-core, and each binding is a thin adapter.

Browser support ​

Modern evergreen browsers. The engine relies on Pointer Events, document.elementsFromPoint and the Web Animations API available everywhere since ~2020. SSR is safe: nothing touches the DOM until a list is constructed in the browser.

Released under the MIT License.