npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pantograph/sortable

v2.2.3

Published

JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.

Readme

Sortable.js

A modern JavaScript library for reorderable drag-and-drop lists with touch support.

Features

  • Touch Support: Works on mobile devices and touch screens
  • Modern Browsers: Full support for all modern browsers (including IE9+)
  • Cross-List Dragging: Drag items between different lists
  • Smooth Animations: CSS animations and transitions
  • Drag Handles: Support for drag handles and selectable text
  • Auto-Scrolling: Smart auto-scroll during drag operations
  • Plugin System: Extensible with plugins
  • Framework Support: Works with React, Vue, Angular, and more
  • No Dependencies: Pure JavaScript, no jQuery required
  • TypeScript: Full TypeScript definitions available

Quick Start

Installation

npm install sortablejs --save

Basic Usage

<ul id="items">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
import Sortable from 'sortablejs';

const el = document.getElementById('items');
const sortable = Sortable.create(el);

Installation Options

NPM

npm install sortablejs --save

CDN

<script src="sortable.min.js"></script>

Import Options

// Default SortableJS (with default plugins)
import Sortable from 'sortablejs';

// Core SortableJS (without plugins)
import Sortable from 'sortablejs/modular/sortable.core.esm.js';

// Complete SortableJS (with all plugins)
import Sortable from 'sortablejs/modular/sortable.complete.esm.js';

// Cherry-pick plugins
import Sortable, { Swap, AutoScroll } from 'sortablejs';

Configuration

Basic Options

const sortable = Sortable.create(el, {
    group: "name",           // Group name for cross-list dragging
    sort: true,              // Enable sorting within list
    delay: 0,                // Delay before drag starts (ms)
    disabled: false,         // Disable the sortable
    animation: 150,          // Animation duration (ms)
    handle: ".drag-handle",  // Drag handle selector
    filter: ".ignore",       // Elements to ignore
    draggable: ".item",      // Draggable elements
    ghostClass: "sortable-ghost",    // Class for drop placeholder
    chosenClass: "sortable-chosen",  // Class for chosen item
    dragClass: "sortable-drag",      // Class for dragging item
    swapThreshold: 0.65,     // Swap zone threshold
    direction: 'vertical',   // Sort direction
    forceFallback: false,    // Force fallback mode
});

Advanced Options

const sortable = Sortable.create(el, {
    // Group configuration
    group: {
        name: "shared",
        pull: true,    // Can pull from this group
        put: true,     // Can put into this group
        revertClone: true  // Revert cloned element
    },
    
    // Animation settings
    animation: 150,
    easing: "cubic-bezier(1, 0, 0, 1)",
    
    // Touch settings
    delayOnTouchOnly: false,
    touchStartThreshold: 3,
    
    // Fallback settings
    fallbackClass: "sortable-fallback",
    fallbackOnBody: false,
    fallbackTolerance: 0,
    
    // Scroll settings
    scroll: true,
    scrollSensitivity: 30,
    scrollSpeed: 10,
    
    // Event handlers
    onStart: function(evt) {
        console.log('Drag started');
    },
    onEnd: function(evt) {
        console.log('Drag ended');
    }
});

Event Handlers

const sortable = Sortable.create(el, {
    // Element is chosen
    onChoose: function(evt) {
        console.log('Element chosen:', evt.item);
    },
    
    // Element is unchosen
    onUnchoose: function(evt) {
        console.log('Element unchosen:', evt.item);
    },
    
    // Element dragging started
    onStart: function(evt) {
        console.log('Drag started:', evt.item);
        console.log('Old index:', evt.oldIndex);
    },
    
    // Element dragging ended
    onEnd: function(evt) {
        console.log('Drag ended');
        console.log('Item:', evt.item);
        console.log('From:', evt.from);
        console.log('To:', evt.to);
        console.log('Old index:', evt.oldIndex);
        console.log('New index:', evt.newIndex);
    },
    
    // Element is added to list
    onAdd: function(evt) {
        console.log('Element added:', evt.item);
    },
    
    // Element is removed from list
    onRemove: function(evt) {
        console.log('Element removed:', evt.item);
    },
    
    // List order changed
    onUpdate: function(evt) {
        console.log('List updated');
    },
    
    // Any change to list
    onSort: function(evt) {
        console.log('List sorted');
    },
    
    // Element is filtered
    onFilter: function(evt) {
        console.log('Element filtered:', evt.item);
    },
    
    // Element is moved
    onMove: function(evt, originalEvent) {
        console.log('Element moved');
        // Return false to cancel
        // Return -1 to insert before
        // Return 1 to insert after
        return true;
    },
    
    // Clone is created
    onClone: function(evt) {
        console.log('Clone created:', evt.clone);
    },
    
    // Element position changed
    onChange: function(evt) {
        console.log('Element changed position');
    }
});

Methods

Instance Methods

const sortable = Sortable.create(el);

// Get/set options
sortable.option('disabled', true);
const disabled = sortable.option('disabled');

// Get array of item IDs
const order = sortable.toArray();

// Sort items by array
sortable.sort(['item3', 'item1', 'item2']);

// Save current order
sortable.save();

// Destroy sortable
sortable.destroy();

Static Methods

// Create new instance
const sortable = Sortable.create(el, options);

// Get instance from element
const sortable = Sortable.get(element);

// Mount plugin
Sortable.mount(Plugin);

// Get active instance
const active = Sortable.active;

// Get dragged element
const dragged = Sortable.dragged;

Plugins

Default Plugins (Included)

  • AutoScroll: Automatic scrolling during drag operations
  • OnSpill: Handle items dropped outside valid targets
    • RemoveOnSpill: Remove spilled items
    • RevertOnSpill: Revert spilled items to original position

Extra Plugins

  • Swap: Swap items instead of reordering
  • FlatTree: Hierarchical tree-like drag and drop

Plugin Usage

import Sortable, { Swap, AutoScroll } from 'sortablejs';

// Mount plugins
Sortable.mount(Swap);
Sortable.mount(AutoScroll);

// Use plugins
const sortable = Sortable.create(el, {
    swap: true,
    scroll: true
});

Examples

Basic List

<ul id="basic-list">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
Sortable.create(document.getElementById('basic-list'));

Drag Handles

<ul id="handle-list">
    <li><span class="handle">⋮⋮</span> Item 1</li>
    <li><span class="handle">⋮⋮</span> Item 2</li>
    <li><span class="handle">⋮⋮</span> Item 3</li>
</ul>
Sortable.create(document.getElementById('handle-list'), {
    handle: '.handle'
});

Cross-List Dragging

<div id="list1" class="list">
    <div class="item">Item 1</div>
    <div class="item">Item 2</div>
</div>
<div id="list2" class="list">
    <div class="item">Item 3</div>
    <div class="item">Item 4</div>
</div>
Sortable.create(document.getElementById('list1'), {
    group: 'shared'
});

Sortable.create(document.getElementById('list2'), {
    group: 'shared'
});

Bootstrap Integration

<ul class="list-group" id="bootstrap-list">
    <li class="list-group-item">Item 1</li>
    <li class="list-group-item">Item 2</li>
    <li class="list-group-item">Item 3</li>
</ul>
Sortable.create(document.getElementById('bootstrap-list'));

Browser Support

  • Modern Browsers: Chrome, Firefox, Safari, Edge
  • Mobile: iOS Safari, Chrome Mobile, Firefox Mobile
  • Legacy: Internet Explorer 9+
  • Touch Devices: Full touch support

Performance Tips

  1. Use Drag Handles: Reduces accidental drags
  2. Limit Animation Duration: Keep animations under 200ms
  3. Use Efficient Selectors: Avoid complex CSS selectors
  4. Disable When Not Needed: Use disabled option
  5. Optimize Event Handlers: Keep handlers lightweight

Contributing

Please read our Contributing Guide before submitting issues or pull requests.

License

MIT License - see LICENSE file for details.