VanillaJS sortable lists and grids using native HTML5 drag and drop API.
npm install html5sortable       
> Lightweight vanillajs micro-library for creating sortable lists and grids using native HTML5 drag and drop API.
A fair warning: this repository is currently not being actively developed. It works pretty fine, but if you find any issues you will need to fix them yourself. I try to keep the dependencies up to date and will happily help you fix issues and merge PRs for bugfixes or new features.
If you are interested in actively helping with maintaining & improving this project please send me a message via twitter @lukasoppermann or email oppermann.lukas@gmail.com with a short text of what you would like to do on the project. This may be something small like sorting issues and helping with questions and small bugs (if you have little time or are not that experienced) or something big like tackling big features.
sortable globalDemo: Check out the examples
```
npm install html5sortable --save
Once you install the package using npm or downloading the latest release (don't use the master branch), load file you need from the dist/ directory, e.g. dist/html.sortable.min.js for the minified iife version.
- iffe (loading file via script tag): dist/html5sortable.js or dist/html5sortable.min.jsdist/html5sortable.es.js
- ES6 Module: dist/html5sortable.cjs.js
- CommonJS Module: dist/html5sortable.amd.js
- AMD Module:
Still using bower? bower install https://github.com/lukasoppermann/html5sortable.git
.Docs
$3
Use
sortable method to create a sortable list:` javascript
sortable('.sortable');
`$3
Use
.sortable-placeholder CSS selectors to change the styles of the placeholder. You may change the class by setting the placeholderClass option in the config object.` javascript
sortable('.sortable', {
placeholderClass: 'my-placeholder fade'
});
`$3
You can nest sortables inside each other. However, take care to add a wrapper around the items, a sortable-item can not at the same time be a sortable.`html
Item 1
Subitem 1
Subitem 2
Item 2
`Events
NOTE: Events can be listened on any element from the group (when using connectWith), since the same event will be dispatched on all of them.$3
Use
sortstart event if you want to do something when sorting starts:` javascript
sortable('.sortable')[0].addEventListener('sortstart', function(e) {
/* This event is triggered when the user starts sorting and the DOM position has not yet changed.
e.detail.item - {HTMLElement} dragged element
Origin Container Data
e.detail.origin.index - {Integer} Index of the element within Sortable Items Only
e.detail.origin.elementIndex - {Integer} Index of the element in all elements in the Sortable Container
e.detail.origin.container - {HTMLElement} Sortable Container that element was moved out of (or copied from)
*/
});
`$3
Use the
sortstop event if you want to do something when sorting stops:` javascript
sortable('.sortable')[0].addEventListener('sortstop', function(e) {
/* This event is triggered when the user stops sorting and the DOM position has not yet changed.
e.detail.item - {HTMLElement} dragged element
Origin Container Data
e.detail.origin.index - {Integer} Index of the element within Sortable Items Only
e.detail.origin.elementIndex - {Integer} Index of the element in all elements in the Sortable Container
e.detail.origin.container - {HTMLElement} Sortable Container that element was moved out of (or copied from)
*/
});
`$3
Use
sortupdate event if you want to do something when the order changes (e.g. storing the new order):` javascript
sortable('.sortable')[0].addEventListener('sortupdate', function(e) { console.log(e.detail);
/*
This event is triggered when the user stopped sorting and the DOM position has changed.
e.detail.item - {HTMLElement} dragged element
Origin Container Data
e.detail.origin.index - {Integer} Index of the element within Sortable Items Only
e.detail.origin.elementIndex - {Integer} Index of the element in all elements in the Sortable Container
e.detail.origin.container - {HTMLElement} Sortable Container that element was moved out of (or copied from)
e.detail.origin.itemsBeforeUpdate - {Array} Sortable Items before the move
e.detail.origin.items - {Array} Sortable Items after the move
Destination Container Data
e.detail.destination.index - {Integer} Index of the element within Sortable Items Only
e.detail.destination.elementIndex - {Integer} Index of the element in all elements in the Sortable Container
e.detail.destination.container - {HTMLElement} Sortable Container that element is moved into (or copied into)
e.detail.destination.itemsBeforeUpdate - {Array} Sortable Items before the move
e.detail.destination.items - {Array} Sortable Items after the move
*/
});
`$3
Fired when a dragitem enters a sortable container.
$3
Fired when a dragitem leaves a sortable container.
Options
$3
Use the items option to specify which items inside the element should be sortable:` javascript
sortable('.sortable', {
items: ':not(.disabled)'
});
`
$3
Use the handle option to restrict drag start to the specified element:` javascript
sortable('.sortable', {
handle: 'h2'
});
`
$3
Setting the forcePlaceholderSize option to true, forces the placeholder to have a height:` javascript
sortable('.sortable', {
forcePlaceholderSize: true
});
`$3
Use acceptFrom instead. The connectWith option allows you to create a connected lists:` javascript
sortable('.js-sortable, .js-second-sortable', {
connectWith: 'connected' // unique string, which is not used for other connectWith sortables
});
`$3
Use the acceptFrom option to restrict which sortable's items will be accepted by this sortable. acceptFrom accepts a comma separated list of selectors or false to disabling accepting items. This is an alternative to the now deprecated connectWith and should not be used together.` javascript
sortable('.sortable', {
acceptFrom: '.sortable, .anotherSortable' // Defaults to null
});
`Note: Using
acceptFrom also effects the sortable itself. This means, items will not be sortable within the list itself, if you do not include it in the acceptFrom option. In the example the current list
.sortable allows items within it to be sorted and accepts elements from .anotherSortable.If you want to be able to move items between to sortables, the
acceptFrom option must be present on both of them.$3
Use the placeholder option to specify the markup of the placeholder:` javascript
sortable('.sortable', {
items: 'tr' ,
placeholder: ' '
});
`$3
Use the hoverClass option to apply css classes to the hovered element rather than relying on :hover. This can eliminate some potential drag and drop issues where another element thinks it is being hovered over. Disabled when disabling or destroying sortable element.` javascript
sortable('.sortable', {
hoverClass: 'is-hovered is-hovered-class' // Defaults to false
});
`$3
Use dropTargetContainerClass option to apply a css Class to the container. The class is added when dragged item enters the container and removed when it leaves it (or is dropped).` javascript
sortable('.sortable', {
dropTargetContainerClass: 'is-drop-target' // Defaults to false
});
`$3
Use the maxItems option to restrict the number of items that can be added to a sortable from a connected sortable. maxItems should always be combined with the items option. Make sure items does not match placeholder and other options, so that they are not counted.` javascript
sortable('.sortable', {
maxItems: 3 // Defaults to 0 (no limit)
});
`
$3
Use the copy option to duplicate the element on drag. The original element will remain in the same position.` javascript
sortable('.sortable', {
copy: true // Defaults to false
});
`$3
Use the orientation option to specify the orientation of your list and fix incorrect hover behaviour. Defaults to 'vertical'.` javascript
sortable('.sortable', {
orientation: 'horizontal' // Defaults to 'vertical'
});
`$3
You can provide a function that will be applied to every item in the items array (see serialize). The function receives two arguments: serializedItem: object, sortableContainer: Element. This function can be used to change the output for the items. Defaults to undefined.` javascript
sortable('.sortable', {
itemSerializer: (serializedItem, sortableContainer) => {
return {
position: serializedItem.index + 1,
html: serializedItem.html
}
}
});
`$3
You can provide a function that will be applied to the container object (see serialize). The function receives one argument: serializedContainer: object. This function can be used to change the output for the container. Defaults to undefined.` javascript
sortable('.sortable', {
containerSerializer: (serializedContainer) => {
return {
length: container.itemCount
}
}
});
`$3
You can provide a function or a selector string as the customDragImage property on the options object which will be used to create the item and position of the drag image (the half-transparent item you see when dragging an element).#### Using a Function
The function gets three parameters, the dragged element, an offset object with the offset values for the offset of the item and the
dragstart event. The function MUST return an object with an element property with an html element as well as a posX and posY property with has the x and y offset for the dragImage.` javascript
sortable('.sortable', {
customDragImage: (draggedElement, elementOffset, event) => {
return {
element: draggedElement,
posX: event.pageX - elementOffset.left,
posY: event.pageY - elementOffset.top
}
}
});
`#### Using a Selector
Alternatively, you can specify a selector string as
customDragImage. When using a selector, the first element matched by the selector will be used as the drag image. Note that if no elements match the selector, the default drag behavior will be used.
`javascript
sortable('.sortable', {
customDragImage: '.custom-drag-image-selector'
});
`##### ElementOffset Object Details
The elementOffset object provided to the custom drag image function includes the following properties, which represent the position of the element relative to the viewport, adjusted for any scrolling:
`javascript
{
left: rect.left + window.scrollX,
right: rect.right + window.scrollX,
top: rect.top + window.scrollY,
bottom: rect.bottom + window.scrollY
}
`Methods
$3
To remove the sortable functionality completely:` javascript
sortable('.sortable', 'destroy');
`$3
To disable the sortable temporarily:` javascript
sortable('.sortable', 'disable');
`$3
To enable a disabled sortable:` javascript
sortable('.sortable', 'enable');
`$3
You can easily serialize a sortable using the serialize command. If you provided an itemSerializer or containerSerializer function in the options object, they will be applied to the container object and the items objects before they are returned.` javascript
sortable('.sortable', 'serialize');// You will receive an object in the following format
[{
container: {
node: sortableContainer,
itemCount: items.length
}
items: [{
parent: sortableContainer,
node: item,
html: item.outerHTML,
index: index(item, items)
}, …]
}, …]
`$3
When you add a new item to a sortable, it will not automatically be a draggable item, so you will need to reinit the sortable. Your previously added options will be preserved.` javascript
sortable('.sortable');
`Sorting table rows
* Initialize plugin on
tbody element (browsers automatically add tbody if you don't)
* Keep in mind that different browsers may display different drag images of the row during the drag action. Webkit browsers seem to hide entire contents of td cell if there are any inline elements inside the td. This may or may not be fixed by setting the td to be position: relative;
* If you add a custom placeholder you must use a tr e.g. placeholder: ", otherwise you will only be able to drop items when hovering the first column.Contributing
This version is maintained by Lukas Oppermann and many other contributors. Thanks for your help! :+1:Contributions are always welcome. Please check out the contribution guidelines to make it fast & easy for us to merge your PR.
Issues: If you create a bug report, please make sure to include a test case showing the issue. The easiest way is to copy the codepen template.
Polyfills: Facing towards the future instead of the past
This project is focusing on modern, evergreen browsers to deliver a fast and small package. While many projects try build features so that it runs in the oldest browser (looking at you IE9), we try to create a fast and pleasant development experience using the language capabilities that the current version of Javascript offers.$3
#### Small and fast package for modern browsers
While a backwards facing approach penalises modern browsers by making them download huge files, we prefer to ship a small package and have outdated browser bear the penalty of the polyfill. An additional benefit is that you might polyfill those features in any case so you don't have any additional load.#### Contribution friendly code base
We try to encourage people to help shape the future of this package and contribute in small or big ways. By removing hard to understand hacks we make it easier for people new to the code base or even Javascript to contribute.
#### Helps browser optimisation
Browser try to performance optimise language features as much as possible. Working around the language to make code work in outdated browser may actually work against this.
$3
We recommend using the Financial Times Polyfill Service which will polyfill only the necessary features for browsers that need a polyfill. It is basically a no-config, easy solution.
`
`$3
Touch support can be achieved by using the DragDropTouch polyfill.
The DragDropTouch polyfill must be included before html5sortable is initialized.Known Issues
$3
- Dragstart not working on buttons
Dragstart event does not fire on button` elements. This effectively disables drag and drop for button elements. See https://caniuse.com/#feat=dragndrop in the known issues section.