ng-hub-ui-sortable provides a complete, modern integration of SortableJS for Angular, letting you build interactive UIs with drag-and-drop functionality in a simple, declarative way.
The library covers simple scenarios like reordering items in a list, as well as advanced cases such as nested lists, item transfer between multiple lists, item cloning, integration with Angular Reactive Forms (FormArray) and Angular Signals (WritableSignal), and full customization via options and events. Every drag-and-drop action syncs automatically with your data model, keeping your app reactive and predictable.
FormArray, and writable signalsnpm install ng-hub-ui-sortable sortablejs
npm install -D @types/sortablejsPeer dependencies: Angular >= 18 and SortableJS >= 1.7.0.
You can also use yarn add ng-hub-ui-sortable sortablejs.
Import the module with global options:
import { SortableModule } from 'ng-hub-ui-sortable';
@NgModule({
imports: [SortableModule.forRoot({ animation: 150 })]
})
export class AppModule {}Create a component with your array:
items = ['Item 1', 'Item 2', 'Item 3'];And use it in the template:
<div [hubSortable]="items" [animation]="150">
@for (item of items; track item) {
<div class="p-2 border">{{ item }}</div>
}
</div>| Input | Type | Description |
|---|---|---|
[hubSortable] | any[] | FormArray | WritableSignal<any[]> | Array, FormArray, or writable signal synchronized with drag-and-drop |
[container] | string | CSS selector of the actual container (optional) |
[options] | Options | SortableJS options object |
[cloneFunction] | (item: any) => any | Custom function to clone items |
All SortableJS options can be provided as individual inputs:
[group] - Group name for multi-list[sort] - Enable/disable sorting[delay] - Delay before starting drag (ms)[disabled] - Disable the sortable[draggable] - CSS selector for draggable items[handle] - CSS selector for the drag handle[animation] - Animation speed (ms)[ghostClass] - CSS class for the ghost element[chosenClass] - CSS class for the chosen element[dragClass] - CSS class for the dragging element[filter] - Filter for non-draggable elements[preventOnFilter] - preventDefault on filter[direction] - Direction ('vertical' | 'horizontal')[swapThreshold] - Swap zone threshold[invertSwap] - Invert swap threshold[fallbackOnBody] - Add ghost to body[fallbackTolerance] - Fallback tolerance (px)[fallbackClass] - CSS class for fallback[forceFallback] - Force fallback activation[touchStartThreshold] - Touch start threshold[emptyInsertThreshold] - Empty insert threshold[delayOnTouchOnly] - Delay on touch only[easing] - Easing function for animation[dataIdAttr] - HTML attribute for data id[removeCloneOnHide] - Remove clone on hideAll events run within the Angular zone:
| Output | Type | Description |
|---|---|---|
(init) | Sortable | Emits the Sortable instance on init |
(start) | SortableEvent | Fires when dragging starts |
(end) | SortableEvent | Fires when dragging ends |
(add) | SortableEvent | Item added from another list |
(remove) | SortableEvent | Item removed to another list |
(update) | SortableEvent | Position updated within the same list |
(sortEvent) | SortableEvent | List sorted (any change) |
(change) | SortableEvent | List changed after adding or removing item |
(choose) | SortableEvent | Item chosen (mouse down) |
(unchoose) | SortableEvent | Item unchosen (mouse up without drag) |
(clone) | SortableEvent | Item cloned in clone mode |
(filterEvent) | SortableEvent | Attempt to drag filtered element |
(move) | { event: MoveEvent; originalEvent: Event } | Fires during drag movement |
// Component
export class MyComponent {
items = ['Item 1', 'Item 2', 'Item 3'];
onDragStart(event: SortableEvent) {
console.log('Drag started:', event);
}
onDragEnd(event: SortableEvent) {
console.log('Drag ended:', event);
}
onUpdate(event: SortableEvent) {
console.log('List updated:', this.items);
}
}<!-- Template -->
<div [hubSortable]="items"
[animation]="200"
[handle]="'.drag-handle'"
(start)="onDragStart($event)"
(end)="onDragEnd($event)"
(update)="onUpdate($event)">
@for (item of items; track item) {
<div class="sortable-item">
<span class="drag-handle">☰</span>
{{ item }}
</div>
}
</div>Explore these live demos to see ng-hub-ui-sortable in action. Each example shows different capabilities and common usage patterns:
Other related components:
This package is a fork of @worktile/ngx-sortablejs, keeping the same API while updating branding and metadata to align with the ng-hub-ui family.
Special thanks to the Worktile team for their great initial work integrating SortableJS with Angular.
Contributions are welcome! Here's how you can help:
git checkout -b feature/my-new-featuregit commit -am 'Add some feature'git push origin feature/my-new-featureIf you find any issues, please report them on: GitHub Issues
If you find this project useful and want to support its development, you can buy me a coffee:

Your support is greatly appreciated and helps maintain and improve this project!
This project is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0).
Based on ng-hub-ui-sortable by Carlos Morcillo
Original: https://github.com/carlos-morcillo/ng-hub-ui-sortable
License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)For more details about the license, see the LICENSE file.