Resortable - v2.0.0-alpha.1
    Preparing search index...

    Resortable - v2.0.0-alpha.1

    Resortable

    Modern TypeScript rewrite of Sortable.js — reorderable drag-and-drop lists.

    Alpha — Not ready for production use. This library is under active development and has not been published to npm. APIs will change. If you need a drag-and-drop library today, use SortableJS.

    Migrating from Sortable.js? See the migration guide for the option/plugin/breaking-change delta.

    • Drag & Drop — HTML5 Drag API + Pointer Events for mouse, touch, and pen
    • Cross-Container — Drag items between lists with shared groups
    • Clone Supportgroup.pull: 'clone' to copy items instead of moving
    • Animations — FLIP-based 60fps reorder animations
    • Accessibility — Full keyboard navigation, ARIA attributes, screen reader support. WCAG 2.1 AA verified via an automated axe-core audit in CI; see docs/accessibility.md for the keyboard contract and ARIA reference.
    • Multi-Drag — Ctrl+Click / Shift+Click selection, drag multiple items together
    • Plugin System — AutoScroll, Swap plugins (extensible architecture)
    • TypeScript — Strict types with full IntelliSense support
    • Small — ~17KB gzipped (ESM)
    npm install resortable
    

    Resortable is not yet published to npm (2.0.0-alpha.1 is the current in-repo version). Until first publish, install from a Git ref: npm install jjeff/resortable.

    Once published, the UMD bundle exposes a window.Sortable global and works without a bundler. Version-pin to avoid surprise breaking changes:

    <!-- unpkg -->
    <script src="https://unpkg.com/resortable@2.0.0-alpha.1/dist/sortable.umd.js"></script>

    <!-- or jsDelivr -->
    <script src="https://cdn.jsdelivr.net/npm/resortable@2.0.0-alpha.1/dist/sortable.umd.js"></script>

    <script>
    // The UMD build attaches the library as `window.Sortable`
    new Sortable(document.getElementById('my-list'), {
    animation: 150,
    });
    </script>

    The ESM build via npm install resortable is the recommended path for app code — it tree-shakes, ships TypeScript types, and integrates with modern bundlers.

    import { Sortable } from 'resortable';

    const sortable = new Sortable(document.getElementById('my-list'), {
    animation: 150,
    ghostClass: 'sortable-ghost',
    onEnd: (evt) => {
    console.log(`Moved from ${evt.oldIndex} to ${evt.newIndex}`);
    }
    });
    new Sortable(element, {
    // Behavior
    group: 'shared', // Group name or { name, pull, put } config
    sort: true, // Allow sorting within list
    disabled: false, // Disable the sortable
    draggable: '.sortable-item', // CSS selector for draggable items
    handle: '.drag-handle', // Restrict drag to handle elements
    filter: 'input, button', // Prevent drag on these elements
    ignore: 'a, img', // Descendants that should NOT initiate drag (default 'a, img')
    delay: 0, // Delay in ms before drag starts
    delayOnTouchOnly: 0, // Touch-specific delay
    touchStartThreshold: 5, // Pixels of movement before cancelling delay

    // Visual
    animation: 150, // Animation duration in ms
    easing: 'cubic-bezier(0.4,0,0.2,1)', // CSS easing
    ghostClass: 'sortable-ghost', // Class on the ghost placeholder
    chosenClass: 'sortable-chosen', // Class on the chosen item
    dragClass: 'sortable-drag', // Class on the dragging item

    // Multi-drag
    multiDrag: false, // Enable multi-selection
    selectedClass: 'sortable-selected', // Class on selected items

    // Accessibility
    enableAccessibility: true, // Keyboard nav + ARIA

    // Events
    onStart: (evt) => {},
    onEnd: (evt) => {},
    onAdd: (evt) => {},
    onRemove: (evt) => {},
    onUpdate: (evt) => {},
    onSort: (evt) => {},
    onChoose: (evt) => {},
    onUnchoose: (evt) => {},
    onClone: (evt) => {},
    onChange: (evt) => {},
    onMove: (evt, originalEvent) => {},
    onSelect: (evt) => {},
    onFilter: (evt) => {},
    });
    // Source list — items are cloned when dragged out
    new Sortable(sourceList, {
    group: { name: 'shared', pull: 'clone', put: false },
    });

    // Target list — accepts items from 'shared' group
    new Sortable(targetList, {
    group: { name: 'shared', pull: true, put: true },
    });
    sortable.toArray()              // Get order as array of data-id values
    sortable.sort(['c','a','b']) // Set order by data-id values
    sortable.option('animation') // Get option value
    sortable.option('animation', 300) // Set option value
    sortable.destroy() // Remove instance and clean up
    Sortable.active    // Currently active Sortable instance
    Sortable.dragged // Currently dragged element
    Sortable.ghost // Ghost placeholder element
    Sortable.clone // Cloned element from the most recent clone operation
    Sortable.get(el) // Get Sortable instance by element
    Sortable.closest(el, selector) // Find closest Sortable ancestor

    // DOM helpers — Sortable.utils.* (note: distinct from the static surface above)
    Sortable.utils.on(el, event, handler) // addEventListener; returns an unsubscribe fn
    Sortable.utils.off(el, event, handler) // removeEventListener (symmetric to on)
    Sortable.utils.index(el) // Element's index within its parent
    Sortable.utils.insertAt(parent, el, index) // Insert el at a specific index in parent
    Sortable.utils.closest(el, selector, ctx?) // Nearest ancestor matching selector, bounded by ctx
    Sortable.utils.toggleClass(el, name, force?) // classList.toggle wrapper
    Sortable.utils.clone(el) // Deep-clone an element (cloneNode(true))
    import { Sortable, PluginSystem } from 'resortable';
    import { registerAllPlugins } from 'resortable/plugins';

    // Register all built-in plugins
    registerAllPlugins();

    const sortable = new Sortable(element, { animation: 150 });
    sortable.usePlugin('AutoScroll');
    sortable.usePlugin('Swap');

    Built-in plugins: AutoScroll, MarqueeSelect, OnSpill, Swap.

    Note: Multi-drag is built into the core — no plugin needed. Set multiDrag: true in options. (The MultiDragPlugin v1-compat shim was removed in #34; see the migration guide.)

    See the Plugin Development Guide for the plugin lifecycle, hook reference, and authoring patterns.

    Full TypeDoc-generated API reference: jjeff.github.io/resortable/api/ (coming soon — TypeDoc-generated, deployed via GitHub Pages).

    First-class wrappers for React, Vue, and Svelte are on the roadmap but not yet shipped. Resortable works today with any framework via the imperative new Sortable(element, options) API on a ref/useEffect-mounted element. See #44 for the v2.0 master roadmap, where framework-wrapper packages are tracked.

    The repo ships with a curated set of nine standalone examples covering the v2 API surface — basic list, shared lists, kanban board, clone mode, swap, multi-drag, handle + filter, accessibility, and a custom plugin.

    Live examples: https://jjeff.github.io/resortable/demo/examples/

    To run them against the source locally, see ./examples/index.html (clone the repo and npm run dev, then open http://localhost:5173/examples/index.html).

    npm install          # Install dependencies
    npm run dev # Start Vite dev server
    npm run build # Build library (ESM, CJS, UMD)
    npm run test # Run unit tests (Vitest)
    npm run test:e2e # Run E2E tests (Playwright)
    npm run type-check # TypeScript strict check
    npm run lint # ESLint

    See ARCHITECTURE.md for module documentation.

    Module Purpose
    core/DragManager Drag interaction handling (HTML5 + Pointer Events)
    core/DropZone Container management and DOM operations
    core/EventSystem Type-safe event emitter
    core/GlobalDragState Cross-zone drag coordination
    core/GroupManager Group config and clone detection
    core/GhostManager Ghost/placeholder elements
    core/KeyboardManager Keyboard navigation
    core/SelectionManager Multi-item selection
    core/PluginSystem Plugin lifecycle management
    animation/AnimationManager FLIP-based animations

    MIT © 2025-2026 Jeff Robbins

    Resortable is a TypeScript rewrite of SortableJS by Lebedev Konstantin and the SortableJS contributors. The original library pioneered the drag-and-drop patterns this project builds on, and the legacy source under legacy-sortable/ is consulted for v1 parity. See NOTICE for full attribution.