Sortable

Sortable is a simple JavaScript class, that implements a small, fast and fairly robust “sortable” interaction.

Component

The sortable component is a helper that makes a list of HTMLElement s sortable.

new Sortable(container, config);
parameters
nametypedescription
containerHTMLElementThe parent container of the sortable items
configSortableConfigSee below.

When passing a drag handle, the item itself is not draggable, but only when touching the drag handle.

The component can be configured:

{
    items: string,
    handle?: string,
}
parameters
nametypedescription
itemsstringThe selector string to query for the sortable (= movable) items.
config.handlestring|undefinedA selector (inside of the item) to query for the drag handle element.

Example

Given the HTML structure:

<ul id="sortable-example">
    <li class="list-item">Entry 1</li>
    <li class="list-item">Entry 2</li>
    <li class="list-item">Entry 3</li>
</ul>

you can integrate the sortable like this:

let container = document.getElementById("sortable-example");

let sortable = new Sortable(container, {
    items: ".list-item",
    handle: ".drag-handle"
});

// register event listener
sortable.on(
    "changed",
    (items, result) => {}
);

// Don't forget to actually initialize the component
sortable.init();

// you can also destroy the sortable, to remove all DOM integrations
sortable.destroy();

// later you can recreate it
sortable.init();

Events

changed

The event is triggered if the order of the items has changed. It is not triggered if you release the dragged item at the same place as it was before.

(items, result) => { /* ... */ }
parameters
nametypedescription
itemsHTMLElement[]The HTMLElement s in the new order.
result.itemHTMLElementThe HTMLElement that was moved.
result.beforeHTMLElement|nullThe HTMLElement the moved item was inserted before. If null, the item was moved to the end of the list.

start

The event is triggered as soon as dragging an item has started.

(item) => { /* ... */ }
parameters
nametypedescription
itemHTMLElementThe dragged item.

end

The event is triggered as soon as dragging has stopped (by dropping or aborting).

The event handler doesn’t receive any arguments.

Hook

New in version 5.8.0: The hook was added in v5.8.0.

There is also a preact hook, that eases the implementation in JSX components:

import {useSortable} from "mojave/ui/hooks";
import {createRef, h, JSX} from "preact";

export function MyComponent (props: {items: Item[]}): JSX.Element|null
{
    let containerRef = createRef();

    useSortable(
        containerRef,
        {items: "li"}, // these are just the options from a regular sortable
        (item, before) => console.log("Moved item with ID ", item, " before item with ID ", before, " \\o/")
    );

    return (
        <ul ref={containerRef}>
        {props.items.map(item => (
            <li data-id={item.id}>{item.label}</li>
        )}
        </ul>
    );
}

The hook has the following signature:

useSortable(
    ref: RefObject<HTMLElement>,
    config: SortableConfig,
    onChange: (item: number, before: number|null) => void,
    idFetcher?: (element: HTMLElement) => number,
);
parameters
nametypedescription
refRefObject<HTMLElement>The reference to the container element.
configSortableConfigConfiguration to init the sortable.
onChangeFunctionThe callback which is called as soon as the order has changed.
idFetcherFunctionA function that receives an HTMLElement and returns the ID of the element. By default it looks at the data-id attribute.

The config is the SortableConfig from above.

The onChange callback receives two parameters:

  • item (number) the ID of the item that was moved.
  • before (number|null) the ID of the item it was moved before. If before is null the item was moved to the end of the list.

This implementation also supports sorting elements on a paginated list. The meaning of “moved to the end of the list” changes then to “to the end of the page”.

The idFetcher is responsible for receiving an HTMLElement and returning the ID from it. The default implementation looks at the data-id attribute.