# 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.

Key Features:

- 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="plugins/sortablejs/sortable.js"</script>

Initialize Sortable on any container element that holds sortable items:

    // Basic initialization
    new Sortable(document.getElementById('list'), {
        // options
    });

Pro Tip: For optimal performance, apply Sortable to the container element rather than individual items. The library will automatically handle the draggable behavior for all child elements.

## 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>

Note: Sortable works with any element type, not just lists. You can use divs, cards, or any other container structure.

## 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').

Pro Tip: Use the `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);
        }
    });

Event Object Properties:

- `item`: The dragged element
- `from`: Source list
- `to`: Destination list
- `oldIndex`: Element's old index within the source list
- `newIndex`: Element's new index within the destination list
- `oldDraggableIndex`: Element's old index within the source list, only counting draggable elements
- `newDraggableIndex`: 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

Pro Tip: Use the `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'
    });

Note: Some plugins may require additional CSS to properly style the interaction states.

## 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'
    });

Pro Tip: For complex applications, consider using the `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: 0` option to improve performance.
- Mobile Support: Set `delayOnTouchOnly: true` and `delay: 100` for better touch device experience.
- Accessibility: Add appropriate ARIA attributes to sortable elements to improve accessibility.
- Feedback: Use the `chosenClass` and `ghostClass` options 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 `onEnd` event to save the new order to your database or localStorage.
- Drag Handles: For complex items, use the `handle` option 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)

Note: For IE11 support, you may need to include additional polyfills for ES6 features.

## Troubleshooting

Common Issues:

- 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 `group` name and that `pull` and `put` options are correctly set.
- Dragging starts immediately on touch devices? Add a `delay` and set `delayOnTouchOnly: true`.
- Ghost element looks wrong? Customize the appearance with `ghostClass` or 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.

##### On This Page

- Introduction
- Installation
- HTML Structure
- Configuration
- Events
- Methods
- Plugins
- Usage Examples
- Best Practices
- Browser Support
- Troubleshooting

#### Hi Sunny,

how can I help you today?
Analyze my data

Create a new report

Summarize my Calendar

App Builder
Unlock limitless design potential with 16+ layout combinations and extensive customization options—tailor your dashboard to fit your exact needs.
Header position fixed
Navigation full height
Navigation position fixed
Navigation collapsed
Navigation Minified
Dark Navigation
Colorblind Mode
High Contrast Mode