SortableJS
Turning Chaos into Click-and-Drag Order!
Sortable.js is a powerful JavaScript library that enables drag-and-drop interactions for reordering elements within lists and grids. It provides a smooth, intuitive way for users to reorganize content with minimal code implementation.
- Drag and drop sorting for lists, grids, and nested structures
 - Touch device support for mobile-friendly interactions
 - Cross-list sorting capabilities
 - Animation effects during sorting operations
 - Customizable drag handles
 - Event hooks for complete control over the sorting process
 - Support for multiple item selection and manipulation
 
Installation
Include Sortable.js in your project by adding the script to your HTML file:
<script src="path/to/sortable.js"</script>
                                        Initialize Sortable on any container element that holds sortable items:
// Basic initialization
new Sortable(document.getElementById('list'), {
    // options
});
                                        HTML Structure
Sortable.js works with virtually any HTML structure. The most common pattern is a list of items:
<!-- Simple list -->
<ul id="simple-list">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
</ul>
<!-- Grid layout -->
<div id="grid-demo" class="row">
    <div class="col-3">Item 1</div>
    <div class="col-3">Item 2</div>
    <div class="col-3">Item 3</div>
    <div class="col-3">Item 4</div>
</div>
<!-- Nested lists -->
<ul id="nested-demo">
    <li>Item 1
        <ul>
            <li>Subitem 1.1</li>
            <li>Subitem 1.2</li>
        </ul>
    </li>
    <li>Item 2</li>
</ul>
                                        Configuration Options
Sortable.js offers numerous configuration options to customize its behavior:
| Option | Type | Default | Description | 
|---|---|---|---|
group | 
                                                        String or Object | null | 
                                                        Group name or configuration for shared lists. Enables drag between lists with the same group name. | 
sort | 
                                                        Boolean | true | 
                                                        Enables sorting within list. | 
delay | 
                                                        Number | 0 | 
                                                        Time in milliseconds to define when the sorting should start. | 
delayOnTouchOnly | 
                                                        Boolean | false | 
                                                        Only delay if user is using touch. | 
animation | 
                                                        Number | 150 | 
                                                        Animation speed in milliseconds. | 
handle | 
                                                        String | null | 
                                                        CSS selector for the drag handle element within list items. | 
filter | 
                                                        String | null | 
                                                        CSS selector for elements that should not be draggable. | 
draggable | 
                                                        String | >* | 
                                                        CSS selector for draggable items within the container. | 
ghostClass | 
                                                        String | sortable-ghost | 
                                                        Class name for the drop placeholder. | 
chosenClass | 
                                                        String | sortable-chosen | 
                                                        Class name for the chosen item. | 
dragClass | 
                                                        String | sortable-drag | 
                                                        Class name for the dragging item. | 
swapThreshold | 
                                                        Number | 1 | 
                                                        Threshold of the swap zone (0 to 1). | 
invertSwap | 
                                                        Boolean | false | 
                                                        Inverts the swap zone if set to true. | 
direction | 
                                                        String | null | 
                                                        Direction of sorting ('vertical', 'horizontal'). | 
group option with { name: 'shared', pull: true, put: true } to enable drag-and-drop between multiple lists.
                                        Events
Sortable.js provides a rich set of events to hook into the sorting lifecycle:
new Sortable(element, {
    // Event callbacks
    onStart: function(evt) {
        // Element dragging started
        console.log('Drag started', evt.oldIndex);
    },
    onEnd: function(evt) {
        // Element dragging ended
        console.log('Drag ended', evt.oldIndex, evt.newIndex);
    },
    onAdd: function(evt) {
        // Element is dropped into the list from another list
        console.log('Item added', evt.item);
    },
    onUpdate: function(evt) {
        // Changed position within list
        console.log('Item position changed', evt.oldIndex, evt.newIndex);
    },
    onSort: function(evt) {
        // Called during sorting
        console.log('Sorting in progress');
    },
    onRemove: function(evt) {
        // Element is removed from the list into another list
        console.log('Item removed', evt.item);
    },
    onChange: function(evt) {
        // Element changed list or position
        console.log('Change occurred', evt);
    }
});
                                        item: The dragged elementfrom: Source listto: Destination listoldIndex: Element's old index within the source listnewIndex: Element's new index within the destination listoldDraggableIndex: Element's old index within the source list, only counting draggable elementsnewDraggableIndex: Element's new index within the destination list, only counting draggable elements
Methods
Sortable.js provides several methods for programmatic control:
// Create a Sortable instance
const sortable = new Sortable(document.getElementById('list'), {
    // options
});
// Get the order of items as an array of IDs
const order = sortable.toArray();
// Sort elements in a predefined order
sortable.sort(['item-3', 'item-1', 'item-2']);
// Destroy the Sortable instance
sortable.destroy();
// Save the current order
const savedOrder = sortable.save();
// Option getter/setter
const currentAnimation = sortable.option('animation'); // getter
sortable.option('animation', 300); // setter
                                        toArray() method to get the current order of items, which is useful for saving the state to a database.
                                        Plugins
Sortable.js includes several built-in plugins that extend its functionality:
| Plugin | Description | 
|---|---|
AutoScroll | 
                                                        Automatically scrolls the window when dragging near the edges. | 
MultiDrag | 
                                                        Enables selecting and dragging multiple items simultaneously. | 
Swap | 
                                                        Allows direct swapping of items instead of sorting. | 
Revert | 
                                                        Reverts items to their original position if dropped outside valid targets. | 
Remove | 
                                                        Removes items when dropped outside valid targets. | 
To use a plugin, you need to activate it and configure it in your Sortable initialization:
// Enable MultiDrag plugin
Sortable.mount(new MultiDrag());
// Initialize with plugin options
new Sortable(element, {
    multiDrag: true,
    selectedClass: 'selected',
    multiDragKey: 'CTRL'
});
                                        Usage Examples
Basic Sortable List
// Simple sortable list
new Sortable(document.getElementById('simple-list'), {
    animation: 150,
    ghostClass: 'blue-background-class'
});
                                        Shared Lists with Drag Between
// List A
new Sortable(document.getElementById('list-a'), {
    group: 'shared',
    animation: 150
});
// List B
new Sortable(document.getElementById('list-b'), {
    group: 'shared',
    animation: 150
});
                                        Kanban Board
// Initialize each column as a Sortable list
document.querySelectorAll('.kanban-column').forEach(column => {
    new Sortable(column, {
        group: 'kanban',
        animation: 150,
        ghostClass: 'blue-background-class',
        onEnd: function(evt) {
            // Update task status based on the column it was moved to
            const taskId = evt.item.dataset.id;
            const newStatus = evt.to.dataset.status;
            updateTaskStatus(taskId, newStatus);
        }
    });
});
                                        Nested Lists
// Initialize parent list
new Sortable(document.getElementById('nested-parent'), {
    group: 'nested',
    animation: 150
});
// Initialize all child lists
document.querySelectorAll('.nested-child').forEach(list => {
    new Sortable(list, {
        group: 'nested',
        animation: 150
    });
});
                                        Using MultiDrag Plugin
// Mount the MultiDrag plugin
Sortable.mount(new MultiDrag());
// Initialize with MultiDrag options
new Sortable(document.getElementById('multi-list'), {
    animation: 150,
    multiDrag: true,
    selectedClass: 'selected',
    multiDragKey: 'CTRL'
});
                                        store option to automatically save and restore the sort order using localStorage or a server API.
                                        Best Practices
- Performance: For large lists (100+ items), consider using the 
animation: 0option to improve performance. - Mobile Support: Set 
delayOnTouchOnly: trueanddelay: 100for better touch device experience. - Accessibility: Add appropriate ARIA attributes to sortable elements to improve accessibility.
 - Feedback: Use the 
chosenClassandghostClassoptions to provide visual feedback during drag operations. - Nested Lists: When working with nested lists, ensure each list has the same group name but unique IDs.
 - Saving State: Use the 
onEndevent to save the new order to your database or localStorage. - Drag Handles: For complex items, use the 
handleoption to specify a drag handle to prevent accidental dragging when interacting with other elements. 
Browser Support
Sortable.js supports all modern browsers including:
- Chrome
 - Firefox
 - Safari
 - Edge
 - IE11 (with polyfills)
 - Mobile browsers (iOS Safari, Chrome for Android)
 
Troubleshooting
- Items not draggable? Check that your selector matches the items and that they don't have 
position: static. - Can't drag between lists? Ensure both lists have the same 
groupname and thatpullandputoptions are correctly set. - Dragging starts immediately on touch devices? Add a 
delayand setdelayOnTouchOnly: true. - Ghost element looks wrong? Customize the appearance with 
ghostClassor adjust your CSS. - Events not firing? Check that your event handlers are properly bound and that the Sortable instance is correctly initialized.
 - Nested sortable not working? Ensure each nested list has its own Sortable instance with the same group name.
 - Performance issues with large lists? Reduce or disable animation, or implement virtual scrolling for very large datasets.