html5sortable
VanillaJS sortable lists and grids using native HTML5 drag and drop API.
Top Related Projects
Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
:ok_hand: Drag and drop so simple it hurts
Infinite responsive, sortable, filterable and draggable layouts
The JavaScript Drag & Drop library your grandparents warned you about.
VanillaJS sortable lists and grids using native HTML5 drag and drop API.
Quick Overview
HTML5sortable is a lightweight JavaScript library that enables drag-and-drop sorting functionality for HTML elements. It leverages the HTML5 drag and drop API, providing a native and efficient solution for creating sortable lists and grids without external dependencies.
Pros
- Lightweight and dependency-free, resulting in faster load times and better performance
- Supports both vertical and horizontal sorting
- Highly customizable with various options and callbacks
- Works across modern browsers and devices, including touch-enabled devices
Cons
- Limited built-in styling options, requiring custom CSS for advanced visual customization
- May require additional code for complex sorting scenarios or nested sortables
- Documentation could be more comprehensive, especially for advanced use cases
Code Examples
- Basic sortable list:
sortable('.sortable-list');
This code initializes a sortable list for elements with the class 'sortable-list'.
- Sortable with options:
sortable('.sortable-grid', {
forcePlaceholderSize: true,
placeholderClass: 'ph-class',
dragHandle: '.handle'
});
This example creates a sortable grid with custom options, including a forced placeholder size, custom placeholder class, and a specific drag handle.
- Event handling:
sortable('.sortable-list', {
dragStart: (e) => {
console.log('Drag started', e.detail);
},
dragEnd: (e) => {
console.log('Drag ended', e.detail);
}
});
This code demonstrates how to add event listeners for drag start and end events.
Getting Started
- Include the HTML5sortable script in your HTML file:
<script src="https://cdn.jsdelivr.net/npm/html5sortable@0.13.3/dist/html5sortable.min.js"></script>
- Create an HTML structure for your sortable elements:
<ul class="sortable-list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
- Initialize the sortable functionality:
sortable('.sortable-list');
That's it! Your list is now sortable using drag and drop.
Competitor Comparisons
Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
Pros of Sortable
- More feature-rich with advanced functionality like multi-drag, swap, and animation
- Supports touch devices and works with mobile interfaces
- Larger community and more frequent updates
Cons of Sortable
- Larger file size and potentially higher performance overhead
- Steeper learning curve due to more complex API and options
- May be overkill for simple sorting needs
Code Comparison
html5sortable:
sortable('.sortable', {
forcePlaceholderSize: true,
placeholderClass: 'my-placeholder'
});
Sortable:
new Sortable(document.querySelector('.sortable'), {
animation: 150,
ghostClass: 'blue-background-class',
onEnd: function(evt) {
// Custom logic after sorting
}
});
Both libraries offer straightforward initialization, but Sortable provides more options and callbacks out of the box. html5sortable focuses on simplicity and follows HTML5 native drag and drop specifications more closely.
html5sortable is lightweight and easy to use for basic sorting needs, while Sortable offers a more comprehensive solution with advanced features and better mobile support. The choice between them depends on the specific requirements of your project, such as complexity, performance needs, and target devices.
:ok_hand: Drag and drop so simple it hurts
Pros of Dragula
- More feature-rich, supporting drag and drop between containers
- Smoother animations and visual feedback during drag operations
- Extensive API for customization and event handling
Cons of Dragula
- Larger file size and potentially higher performance overhead
- Steeper learning curve due to more complex API and configuration options
- May require more setup for basic sorting functionality
Code Comparison
HTML5sortable:
sortable('.sortable-list', {
forcePlaceholderSize: true,
placeholderClass: 'ph-class'
});
Dragula:
dragula([document.querySelector('.sortable-list')], {
moves: function (el, container, handle) {
return handle.classList.contains('handle');
}
});
Summary
HTML5sortable is a lightweight, easy-to-use library focused on sorting within a single container. It's ideal for simple sorting tasks and has a smaller footprint.
Dragula offers more advanced features, including cross-container drag and drop, but comes with a larger file size and more complex setup. It's better suited for projects requiring sophisticated drag and drop functionality.
Choose HTML5sortable for straightforward sorting needs, and Dragula for more complex drag and drop requirements.
Infinite responsive, sortable, filterable and draggable layouts
Pros of Muuri
- More feature-rich, offering advanced grid layouts and animations
- Supports both vanilla JavaScript and React implementations
- Better performance for large datasets and complex layouts
Cons of Muuri
- Steeper learning curve due to more complex API
- Larger file size, which may impact load times for smaller projects
- Less focus on accessibility compared to html5sortable
Code Comparison
html5sortable:
sortable('.sortable-list', {
forcePlaceholderSize: true,
placeholderClass: 'my-placeholder'
});
Muuri:
const grid = new Muuri('.grid', {
dragEnabled: true,
layoutOnInit: false,
dragSortHeuristics: {
sortInterval: 50
}
});
Key Differences
- html5sortable is focused on simple, accessible drag-and-drop sorting
- Muuri offers more advanced grid layouts and animations
- html5sortable has a smaller footprint and simpler API
- Muuri provides better performance for complex layouts and large datasets
- html5sortable emphasizes accessibility, while Muuri prioritizes features and flexibility
Both libraries have their strengths, and the choice between them depends on project requirements, complexity, and performance needs.
The JavaScript Drag & Drop library your grandparents warned you about.
Pros of Draggable
- More comprehensive feature set, including multiple drag and drop libraries for different use cases
- Better performance for complex drag and drop scenarios
- Extensive documentation and examples
Cons of Draggable
- Larger file size and potentially more complex implementation
- Steeper learning curve for basic drag and drop functionality
Code Comparison
html5sortable:
sortable('.sortable', {
forcePlaceholderSize: true,
placeholderClass: 'my-placeholder'
});
Draggable:
new Draggable.Sortable(document.querySelectorAll('.sortable'), {
draggable: 'li',
mirror: {
appendTo: 'body',
constrainDimensions: true
}
});
Summary
html5sortable is a lightweight, easy-to-use library for basic sorting functionality, while Draggable offers a more robust set of features for complex drag and drop scenarios. html5sortable is ideal for simple projects or when minimizing file size is crucial, whereas Draggable shines in larger applications that require advanced drag and drop capabilities. The choice between the two depends on the specific needs of your project and the level of complexity you're willing to manage.
VanillaJS sortable lists and grids using native HTML5 drag and drop API.
Pros of html5sortable
- Lightweight and easy to use
- Supports touch devices and multiple connected lists
- No jQuery dependency, pure JavaScript implementation
Cons of html5sortable
- Limited customization options compared to some alternatives
- May require additional plugins for advanced features
- Documentation could be more comprehensive
Code Comparison
Both repositories contain the same codebase, as they are the same project. Here's a sample of the core functionality:
sortable('.sortable', {
forcePlaceholderSize: true,
placeholderClass: 'my-placeholder fade'
});
This code initializes the sortable functionality on elements with the 'sortable' class, setting a custom placeholder class and forcing its size.
Summary
html5sortable is a lightweight, vanilla JavaScript library for creating sortable lists and grids using HTML5 drag and drop API. It's easy to implement and works well for basic sorting needs. However, for more complex sorting requirements or extensive customization, developers might need to look for additional solutions or plugins.
The repository comparison in this case is not applicable, as both repositories refer to the same project. The confusion might have arisen from a typo or misunderstanding in the original request.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Community maintained
[!WARNING] 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.
HTML5Sortable
Lightweight vanillajs micro-library for creating sortable lists and grids using native HTML5 drag and drop API.
Table of Contents
- Community maintained
- Looking for Co-Maintainer
- Features
- Framework adapters
- Installation
- Examples
- Docs
- Contributing
- Polyfills
- Touch Support
- Known Issues
Looking for Co-Maintainer
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.
Features
- Only 2KB (minified and gzipped).
- Built using native HTML5 drag and drop API. No dependencies.
- Supports both list and grid style layouts.
- Supported Browsers: Current versions of all major browsers (Chrome, Firefox, Safari, Opera, Edge), IE11+ (Polyfill required)
- Available as ES6 Module, AMD, CommonJS and iffe with
sortable
global
Demo: Check out the examples
Framework adapters
If you would like to add an adapter to the list, please create an issue with the link to your adapter.
Installation
We recommend installing the package via npm.
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
ordist/html5sortable.min.js
- ES6 Module:
dist/html5sortable.es.js
- CommonJS Module:
dist/html5sortable.cjs.js
- AMD Module:
dist/html5sortable.amd.js
Still using bower? bower install https://github.com/lukasoppermann/html5sortable.git
Examples
You can find the examples online or test locally. Warning: the online demo is just to show off the features and is most likely not up to date. Please study this readme file for the current way of implementing and using html5sortable
.
Docs
Usage
Use sortable
method to create a sortable list:
sortable('.sortable');
Styling
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.
sortable('.sortable', {
placeholderClass: 'my-placeholder fade'
});
Nesting
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
.
<div class="list"><!-- Sortable -->
<div class="item"> Item 1
<div class="sublist"><!-- Nested Sortable; Wrapping container needed -->
<div class="subitem">Subitem 1</div>
<div class="subitem">Subitem 2</div>
</div>
</div>
<div class="item"> Item 2 </div>
</div>
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.
sortstart
Use sortstart
event if you want to do something when sorting starts:
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)
*/
});
sortstop
Use the sortstop
event if you want to do something when sorting stops:
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)
*/
});
sortupdate
Use sortupdate
event if you want to do something when the order changes (e.g. storing the new order):
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
*/
});
sortenter
Fired when a dragitem enters a sortable container.
sortleave
Fired when a dragitem leaves a sortable container.
Options
items
Use the items
option to specify which items inside the element should be sortable:
sortable('.sortable', {
items: ':not(.disabled)'
});
handle
Use the handle
option to restrict drag start to the specified element:
sortable('.sortable', {
handle: 'h2'
});
forcePlaceholderSize
Setting the forcePlaceholderSize
option to true, forces the placeholder to have a height:
sortable('.sortable', {
forcePlaceholderSize: true
});
connectWith
Use acceptFrom
instead. The connectWith
option allows you to create a connected lists:
sortable('.js-sortable, .js-second-sortable', {
connectWith: 'connected' // unique string, which is not used for other connectWith sortables
});
acceptFrom
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.
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.
placeholder
Use the placeholder
option to specify the markup of the placeholder:
sortable('.sortable', {
items: 'tr' ,
placeholder: '<tr><td colspan="7"> </td></tr>'
});
hoverClass
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.
sortable('.sortable', {
hoverClass: 'is-hovered is-hovered-class' // Defaults to false
});
dropTargetContainerClass
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).
sortable('.sortable', {
dropTargetContainerClass: 'is-drop-target' // Defaults to false
});
maxItems
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.
sortable('.sortable', {
maxItems: 3 // Defaults to 0 (no limit)
});
copy
Use the copy
option to duplicate the element on drag. The original element will remain in the same position.
sortable('.sortable', {
copy: true // Defaults to false
});
orientation
Use the orientation
option to specify the orientation of your list and fix incorrect hover behaviour. Defaults to 'vertical'
.
sortable('.sortable', {
orientation: 'horizontal' // Defaults to 'vertical'
});
itemSerializer
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
.
sortable('.sortable', {
itemSerializer: (serializedItem, sortableContainer) => {
return {
position: serializedItem.index + 1,
html: serializedItem.html
}
}
});
containerSerializer
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
.
sortable('.sortable', {
containerSerializer: (serializedContainer) => {
return {
length: container.itemCount
}
}
});
customDragImage
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.
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.
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:
{
left: rect.left + window.scrollX,
right: rect.right + window.scrollX,
top: rect.top + window.scrollY,
bottom: rect.bottom + window.scrollY
}
Methods
destroy
To remove the sortable functionality completely:
sortable('.sortable', 'destroy');
disable
To disable the sortable temporarily:
sortable('.sortable', 'disable');
enable
To enable a disabled sortable:
sortable('.sortable', 'enable');
serialize
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.
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)
}, â¦]
}, â¦]
reload
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.
sortable('.sortable');
Sorting table rows
- Initialize plugin on
tbody
element (browsers automatically addtbody
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 thetd
. This may or may not be fixed by setting thetd
to beposition: relative;
- If you add a custom
placeholder
you must use atr
e.g.placeholder: "<tr><td colspan="3">The row will appear here</td></tr>"
, 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.
Benefits
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.
Polyfill
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.
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
Touch Support
Touch support can be achieved by using the DragDropTouch polyfill. The DragDropTouch polyfill must be included before html5sortable is initialized.
Known Issues
Firefox
- Dragstart not working on buttons
Dragstart event does not fire onbutton
elements. This effectively disables drag and drop for button elements. See https://caniuse.com/#feat=dragndrop in the known issues section. - Drag & Drop is not working on iOS
But works in conjunction with DragDropTouch #522.
Top Related Projects
Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
:ok_hand: Drag and drop so simple it hurts
Infinite responsive, sortable, filterable and draggable layouts
The JavaScript Drag & Drop library your grandparents warned you about.
VanillaJS sortable lists and grids using native HTML5 drag and drop API.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot