FormKit’s Drag and Drop is a small library for adding data-first drag and drop sorting and transferring for lists in your app. It’s simple, flexible, framework agnostic, and clocks in at only ~4Kb gzipped.
Check out the docs here!Created by the FormKit team.
Note
Unlike many projects this repository includes the dist directory since the documentation extracts TypeScript types from the build source code.
FormKit Drag and Drop supports Marko v6 via a native tag integration. Because Marko's <lifecycle> tag provides onMount, onUpdate, and onDestroy hooks directly, no separate composable or hook wrapper is needed — the <dnd> tag is the integration.
npm install @formkit/drag-and-dropEnsure your project uses @marko/vite (v5.4+ for Vite 5, v6+ for Vite 8).
Use the := bind shorthand to wire up reactive state with two-way binding:
<let/tapes=[
"Depeche Mode",
"Duran Duran",
"Pet Shop Boys",
"Kraftwerk",
"Tears for Fears",
"Spandau Ballet",
]>
<ul/parent>
<for|tape| of=tapes by="id">
<li>${tape}</li>
</for>
</ul>
<dnd:=tapes parent=parent/>The <dnd> tag is auto-discoverable — no import needed. Simply install @formkit/drag-and-drop and use <dnd> in any .marko template.
If you prefer an explicit import (e.g. to rename the tag or resolve a conflict):
import Dnd from "@formkit/drag-and-drop/marko"
<Dnd:=tapes parent=parent/>Pass a reactive config variable and replace it to trigger an update:
<let/tapes=["Depeche Mode", "Duran Duran", "Pet Shop Boys"]>
<let/config={}>
<ul/parent>
<for|tape| of=tapes by="id">
<li>${tape}</li>
</for>
</ul>
<dnd:=tapes parent=parent config=config/>
<button onClick() { config = { disabled: true }; }>Disable</button>