Developer Programs

Learn

Docs

Drag and Drop

Components > User Interaction > Drag and Drop
Use this component to...
Allow the user to drag items from one location to another, or to reorder items within a list by dragging

Overview

Drag and drop is an intuitive way to re-order items in a list and to move items between lists. The user grabs an item by clicking/pressing on it, drags the item to a new location, then lets go. The item moves to the dropped location. This mirrors real world processes, making it an instantly familiar mechanism.

Your application specifies how the user can drag items within and between lists and detects when items have been dropped, responding to events after an item has been dropped in a new location.

Our drag and drop functionality supports 2 different styling modes for the list items:

  • Stacked: The list items stack vertically. This option works well if the lists are relatively small.
  • Floating: The list items float left-to-right, top-to-bottom. This options works well for larger lists because it saves space.

Development

Web component development

Component reference

sortable
sortable

Allows the user to reorder a list or drag items from one list to another

View the sortable reference doc

Implementation

Start by adding sortablejs to your package.json file and use npm install to install its module.

Package dependencies
"sortablejs": "x.y.z",

Once the package has been installed, add it to your scripts bundle in the angular.json file.

Bundle scripts
"scripts": [
    ...
    "node_modules/sortablejs/Sortable.min.js",
]

Declare a Sortable variable of type any in the component typescript file.

Define the sortable variable
declare var Sortable: any;

Add a <ul> with the rui-drag-list CSS class for each list in which drag-and-drop should be implemented. Use *ngFor to emit an <li> for each list item. Add the rui-drag-item CSS class to each list item if they should stack vertically or the rui-drag-item-float CSS class to each list item if they should float left-to-right. If you’re displaying two or more lists between which items can be dragged, use the same CSS class for all lists, otherwise the list items can look strange as they change shape when dragged from list to list. Store a unique identifier for each list item in the data-id attribute for the <li>. Display the list item text as the content for each <li>.

Define two HTML lists
<ul id="shown-functions" class="rui-drag-list">
    <li *ngFor="let function of shownFunctionList" data-id="{{function.id}}" class="rui-drag-item-float">
        {{function.name}}
    </li>
</ul>

<ul id="available-functions" class="rui-drag-list">
    <li *ngFor="let function of availableFunctionList" data-id="{{function.id}}" class="rui-drag-item-float">
        {{function.name}}
    </li>
</ul>

In ngAfterViewInit(), create a new Sortable object, passing an object parameter that contains the following options:

  • group (string): Use the same value for all lists that you can drag and drop between.
  • sort (boolean): Can the user drag to sort the items within this list?
  • pull (boolean): Can the user drag items out of this list?
  • put (boolean): Can the user drag items into this list?
  • delay (number): Always use a value of 0.
  • animation (number): Always use a value of 150.
  • chosenClass (string): Always use a value of ‘rui-drag-item-chosen’.
  • scroll (boolean): Should the list scroll as the user drags?
  • dataIdAttr (string): The data attribute in the list’s DOM elements that contains the key for the list. In this example, each DOM element for the list stores the item id in data-id, so the dataIdAttr is set to ‘id’.
  • onSort (function): Callback called after the user sorts the list or drags an item into the list.
  • onRemove (function): Callback called after the user drags an item out of the list. The callback takes an evt parameter; evt.item.getAttribute(‘id’) gets the list item’s id (you should retrieve the same value as that set for dataIdAttr).

The example below has two lists: the first is a list of shown functions and the second is a list of available functions. The available list is a master list that contains all available functions, while the shown list is a sorted list of the functions that the user wants to see in the app. The shown functions list can be sorted and can have items dragged to and from it. It has onRemove and onSort callbacks. The available functions list is a simple list of all available functions. The user can drag items between the two lists and can drag to sort the shown list.

Drag and drop configuration
public ngAfterViewInit() {

    var thisObject = this;
    this.shownSortable = new Sortable(document.getElementById('shown-functions'),
        {
            group: 'function-list',
            sort: true,     // User can drag-and-drop within list to sort it
            pull: true,     // User can drag items out of this list
            put: true,      // User can drag items into this list
            delay: 0,
            animation: 150,
            chosenClass: 'rui-drag-item-chosen',
            scroll: true,
            dataIdAttr: 'id',
            onRemove: function (evt: any) {
                // User dragged item out of this list
                thisObject.deleteShownId(evt.item.getAttribute('id'));
            },
            onSort: function (evt: any) {
                // User sorted this list or dragged item into this list
                thisObject.updateShown();
            }
        });
    this.availableSortable = new Sortable(document.getElementById('available-functions'),
        {
            group: 'function-list',
            sort: false,    // User CANNOT drag-and-drop within list to sort it
            pull: true,     // User can drag items out of this list
            put: false,     // User CANNOT drag items into this list
            delay: 0,
            animation: 150,
            chosenClass: 'rui-drag-item-chosen',
            scroll: true,
            dataIdAttr: 'id'
        });
}

If you need to dynamically retrieve the list of sorted ids represented by the drag-and-drop list, call toArray() on the Sortable object itself. It can be helpful to clone the returned array using slice(0) so any subsequent manipulations of the return value don’t update the drag-and-drop list directly.

Cloning the returned array
let shownFunctionIds = this.shownSortable.toArray().slice(0);

Angular component development

Component reference

sortable
sortable

Allows the user to reorder a list or drag items from one list to another

View the sortable reference doc

Implementation

Start by adding sortablejs to your package.json file and use npm install to install its module.

Package dependencies
"sortablejs": "x.y.z",

Once the package has been installed, add it to your scripts bundle in the angular.json file.

Bundle scripts
"scripts": [
    ...
    "node_modules/sortablejs/Sortable.min.js",
]

Declare a Sortable variable of type any in the component typescript file.

Define the sortable variable
declare var Sortable: any;

Add a <ul> with the rui-drag-list CSS class for each list in which drag-and-drop should be implemented. Use *ngFor to emit an <li> for each list item. Add the rui-drag-item CSS class to each list item if they should stack vertically or the rui-drag-item-float CSS class to each list item if they should float left-to-right. If you’re displaying two or more lists between which items can be dragged, use the same CSS class for all lists, otherwise the list items can look strange as they change shape when dragged from list to list. Store a unique identifier for each list item in the data-id attribute for the <li>. Display the list item text as the content for each <li>.

Define two HTML lists
<ul id="shown-functions" class="rui-drag-list">
    <li *ngFor="let function of shownFunctionList" data-id="{{function.id}}" class="rui-drag-item-float">
        {{function.name}}
    </li>
</ul>

<ul id="available-functions" class="rui-drag-list">
    <li *ngFor="let function of availableFunctionList" data-id="{{function.id}}" class="rui-drag-item-float">
        {{function.name}}
    </li>
</ul>

In ngAfterViewInit(), create a new Sortable object, passing an object parameter that contains the following options:

  • group (string): Use the same value for all lists that you can drag and drop between.
  • sort (boolean): Can the user drag to sort the items within this list?
  • pull (boolean): Can the user drag items out of this list?
  • put (boolean): Can the user drag items into this list?
  • delay (number): Always use a value of 0.
  • animation (number): Always use a value of 150.
  • chosenClass (string): Always use a value of ‘rui-drag-item-chosen’.
  • scroll (boolean): Should the list scroll as the user drags?
  • dataIdAttr (string): The data attribute in the list’s DOM elements that contains the key for the list. In this example, each DOM element for the list stores the item id in data-id, so the dataIdAttr is set to ‘id’.
  • onSort (function): Callback called after the user sorts the list or drags an item into the list.
  • onRemove (function): Callback called after the user drags an item out of the list. The callback takes an evt parameter; evt.item.getAttribute(‘id’) gets the list item’s id (you should retrieve the same value as that set for dataIdAttr).

The example below has two lists: the first is a list of shown functions and the second is a list of available functions. The available list is a master list that contains all available functions, while the shown list is a sorted list of the functions that the user wants to see in the app. The shown functions list can be sorted and can have items dragged to and from it. It has onRemove and onSort callbacks. The available functions list is a simple list of all available functions. The user can drag items between the two lists and can drag to sort the shown list.

Drag and drop configuration
public ngAfterViewInit() {

    var thisObject = this;
    this.shownSortable = new Sortable(document.getElementById('shown-functions'),
        {
            group: 'function-list',
            sort: true,     // User can drag-and-drop within list to sort it
            pull: true,     // User can drag items out of this list
            put: true,      // User can drag items into this list
            delay: 0,
            animation: 150,
            chosenClass: 'rui-drag-item-chosen',
            scroll: true,
            dataIdAttr: 'id',
            onRemove: function (evt: any) {
                // User dragged item out of this list
                thisObject.deleteShownId(evt.item.getAttribute('id'));
            },
            onSort: function (evt: any) {
                // User sorted this list or dragged item into this list
                thisObject.updateShown();
            }
        });
    this.availableSortable = new Sortable(document.getElementById('available-functions'),
        {
            group: 'function-list',
            sort: false,    // User CANNOT drag-and-drop within list to sort it
            pull: true,     // User can drag items out of this list
            put: false,     // User CANNOT drag items into this list
            delay: 0,
            animation: 150,
            chosenClass: 'rui-drag-item-chosen',
            scroll: true,
            dataIdAttr: 'id'
        });
}

If you need to dynamically retrieve the list of sorted ids represented by the drag-and-drop list, call toArray() on the Sortable object itself. It can be helpful to clone the returned array using slice(0) so any subsequent manipulations of the return value don’t update the drag-and-drop list directly.

Cloning the returned array
let shownFunctionIds = this.shownSortable.toArray().slice(0);

Design

There are no specific design elements for drag and drop operations.


Support options
Have questions on this topic?
Join the Responsive UI team in Microsoft Teams to connect with the community.
See something in this page that needs to change?
Send us feedback on this page.
Last updated Fri Jul 28 2023