@vielzeug/dnd
v2.2.0
Published
Framework-agnostic drag-and-drop — sortable lists, file-drop zones, and MIME-type filtering
Readme
@vielzeug/dnd
Framework-agnostic drag-and-drop. Drop zones with MIME filtering, sortable lists with drag handles, and explicit connected scopes — zero dependencies.
Package: @vielzeug/dnd · Category: UI Interaction
Key exports: createDropZone, createSortable, createSortableScope, applyReorder, matchesAccept
When to use: File drop zones with MIME filtering and async validation, or sortable lists with keyboard, FLIP animation, and optimistic-update support — zero dependencies.
Related: @vielzeug/ore · @vielzeug/scroll · @vielzeug/refine
@vielzeug/dnd is part of Vielzeug and ships as a zero-dependency TypeScript package with ESM+CJS output.
Installation
pnpm add @vielzeug/dnd
npm install @vielzeug/dnd
yarn add @vielzeug/dndQuick Start
import { createDropZone, createSortable, createSortableScope } from '@vielzeug/dnd';
// Drop zone — with async validation and clipboard paste support
using zone = createDropZone({
element: document.getElementById('dropzone')!,
accept: ['image/*', '.pdf'],
paste: true,
onValidate: async (files, { signal }) => checkServerQuota(files, { signal }),
onDrop: (files) => uploadFiles(files),
onDropRejected: (files) => {
showError(`${files.length} file(s) not accepted`);
},
onHoverChange: (hovered) => {
document.getElementById('dropzone')!.classList.toggle('drag-over', hovered);
},
});
// Connected sortable lists — one scope owns cross-list moves and touch input
using scope = createSortableScope({
onMove: ({ itemId, sourceIds, targetIds }) => saveMove(itemId, sourceIds, targetIds),
touch: true,
});
using sortable = createSortable({
element: document.getElementById('list')!,
getKey: (el) => el.dataset.sortId!,
onBeforeReorder: (from, to) => {
// snapshot element positions here for FLIP animations
},
onReorder: ({ ids }) => {
setOrder(ids);
},
scope,
});Documentation
License
MIT © Helmuth Saatkamp — part of the Vielzeug monorepo.
