Drag and drop
Angular Bootstrap 5 Drag and drop plugin
Drag and Drop plugin built with Bootstrap 5. Examples of draggable list, cards, tables, grid, buttons. Available sort, copy, scroll, disable, delay, nested & other options.
Note: Read the API tab to find all available options and advanced customization
Draggable basic example
By adding mdbDraggable
directive you can make your custom element
draggable.
Drag me!
<div mdbDraggable class="draggable shadow-1-strong">
<p>Drag me!</p>
</div>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Custom container
If you want to have your draggable component in a container, just add
boundaryElement
directive with selector to your component.
Drag me!
<section
#draggableContainer
class="border p-4 mb-4"
style="height: 400px; overflow: hidden;"
>
<div mdbDraggable class="draggable shadow-1-strong" [boundaryElement]="draggableContainer">
<p>Drag me!</p>
</div>
</section>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Blocked axis
Thanks to [lockAxis]
input you can disable x or y axis.
Drag me!
Drag me!
<div mdbDraggable class="draggable shadow-1-strong" [lockAxis]="'x'">
<p>Drag me!</p>
</div>
<div mdbDraggable class="draggable shadow-1-strong" [lockAxis]="'y'">
<p>Drag me!</p>
</div>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Delay
You can set deley of starting dragging by adding
[delay]
input with miliseconds value.
Drag me after one second!
<div mdbDraggable [delay]="1000" class="draggable shadow-1-strong">
<p>Drag me after one second!</p>
</div>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Disabled
You can set your draggable element as disabled by adding
[disabled]
with true
value.
Disabled
<div mdbDraggable [disabled]="true" class="draggable shadow-1-strong">
<p>Disabled</p>
</div>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Scrolling option
When your draggable element is inside a scrollable container your component will scroll its while you will be near the edge.
Drag!
<div mdbDraggable [autoScroll]="true" class="draggable shadow-1-strong">
<p>Drag!</p>
</div>
.draggable {
display: flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: white;
position: relative;
}
.draggable-dragging {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
.draggable-drag-ico {
position: absolute;
top: 10px;
right: 10px;
font-size: 1.5rem;
color: grey;
}
Sortable basic example
By adding mdbSortableContainer
directive you
can add sortable functionality to the items in a container. Note, only elements with mdbDraggable
directive name will be
able to sort.
<div mdbSortableContainer class="sortable-list" (itemDrop)="onDrop($event)">
<div mdbDraggable *ngFor="let item of items" class="sortable-item">{{ item.name }}</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' }
];
onDrop(event: MdbDropEvent) {
moveItemsInContainer(this.items, event.previousIndex, event.newIndex);
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Horizontal example
Sortable list will create no matter how rotated it is.
<div mdbSortableContainer class="sortable-list d-flex" (itemDrop)="onDrop($event)">
<div mdbDraggable *ngFor="let item of items" class="sortable-item">{{ item.name }}</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' }
];
onDrop(event: MdbDropEvent) {
moveItemsInContainer(this.items, event.previousIndex, event.newIndex);
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
width: 100%;
border-bottom: none;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Grid example
Sortable list works with grid as well.
<div mdbSortableContainer class="sortable-list d-flex flex-wrap" (itemDrop)="onDrop($event)">
<div mdbDraggable *ngFor="let item of items" class="sortable-item">{{ item.name }}</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' },
{ name: 'Item 6' },
{ name: 'Item 7' },
{ name: 'Item 8' },
{ name: 'Item 9' },
{ name: 'Item 10' },
{ name: 'Item 11' },
{ name: 'Item 12' },
];
onDrop(event: MdbDropEvent) {
moveItemsInContainer(this.items, event.previousIndex, event.newIndex);
}
};
.sortable-list {
width: 500px;
max-width: 100%;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
justify-content: center;
align-items: center;
width: 125px;
height: 125px;
margin: 15px;
border: 1px solid #ccc;
text-align: center;
user-select: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Multiple tables
By using [containers]
input you can connect your list with other container.
To do
Done
<div class="d-flex">
<div #firstContainer="mdbSortableContainer" mdbSortableContainer [containers]="[secondContainer]" [data]="itemsFirst" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">To do</h4>
<div mdbDraggable [disabled]="item.disabled" *ngFor="let item of itemsFirst" class="sortable-item">{{ item.name }}</div>
</div>
<div #secondContainer="mdbSortableContainer" mdbSortableContainer [containers]="[firstContainer]" [data]="itemsSecond" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Done</h4>
<div mdbDraggable [disabled]="item.disabled" *ngFor="let item of itemsSecond" class="sortable-item">{{ item.name }}</div>
</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, moveItemToNewContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
itemsFirst = [
{ name: 'Item 1', disabled: false },
{ name: 'Item 2', disabled: false },
{ name: 'Item 3', disabled: false },
{ name: 'Item 4', disabled: false },
{ name: 'Item 5', disabled: false },
{ name: 'Disabled', disabled: true }
];
itemsSecond = [
{ name: 'Item 6', disabled: false },
{ name: 'Item 7', disabled: false },
{ name: 'Item 8', disabled: false },
{ name: 'Item 9', disabled: false },
{ name: 'Item 10', disabled: false }
];
onDrop(event: MdbDropEvent) {
if (event.previousContainer === event.newContainer) {
moveItemsInContainer(event.newContainer.data, event.previousIndex, event.newIndex);
} else {
moveItemToNewContainer(
event.previousContainer.data,
event.newContainer.data,
event.previousIndex,
event.newIndex
);
}
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Coping items
By adding [copy]
input with value true
you can copy your items to
connected table.
Elements
Copy
<div class="d-flex">
<div #firstContainer="mdbSortableContainer" mdbSortableContainer [containers]="[secondContainer]" [data]="itemsFirst" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Elements</h4>
<div mdbDraggable [copy]="item.copy" *ngFor="let item of itemsFirst" class="sortable-item">{{ item.name }}</div>
</div>
<div #secondContainer="mdbSortableContainer" mdbSortableContainer [containers]="[firstContainer]" [data]="itemsSecond" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Copy</h4>
<div mdbDraggable *ngFor="let item of itemsSecond" class="sortable-item">{{ item.name }}</div>
</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, copyItemToNewContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
itemsFirst = [
{ name: 'Item 1', copy: true },
{ name: 'Item 2', copy: true },
{ name: 'Item 3', copy: true },
{ name: 'Item 4', copy: true },
{ name: 'Item 5', copy: true },
];
itemsSecond = [
{ name: 'Item 6' },
{ name: 'Item 7' },
{ name: 'Item 8' },
{ name: 'Item 9' },
{ name: 'Item 10' },
];
onDrop(event: MdbDropEvent) {
if (event.previousContainer === event.newContainer) {
moveItemsInContainer(event.newContainer.data, event.previousIndex, event.newIndex);
} else {
copyItemToNewContainer(
event.previousContainer.data,
event.newContainer.data,
event.previousIndex,
event.newIndex
);
}
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Conditions
You can set your own conditions about permission to sending or coping items to connected table
by adding your custom function with true
/ false
return to
[enterPredicate]
input.
Numbers
Only odd numbers
<div class="d-flex">
<div #firstContainer="mdbSortableContainer" mdbSortableContainer [containers]="[secondContainer]" [data]="itemsFirst" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Numbers</h4>
<div mdbDraggable [data]="item.data" *ngFor="let item of itemsFirst" class="sortable-item">{{ item.name }}</div>
</div>
<div #secondContainer="mdbSortableContainer" mdbSortableContainer [containers]="[firstContainer]" [data]="itemsSecond" [enterPredicate]="enterPredicate" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Only odd numbers</h4>
<div mdbDraggable [data]="item.data" *ngFor="let item of itemsSecond" class="sortable-item">{{ item.name }}</div>
</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, moveItemToNewContainer, MdbDropEvent, MdbDraggableDirective } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
itemsFirst = [
{ name: 'Item 1', data: '1' },
{ name: 'Item 2', data: '2' },
{ name: 'Item 3', data: '3' },
{ name: 'Item 4', data: '4' },
{ name: 'Item 5', data: '5' },
];
itemsSecond = [
{ name: 'Item 7', data: '7' },
];
onDrop(event: MdbDropEvent) {
if (event.previousContainer === event.newContainer) {
moveItemsInContainer(event.newContainer.data, event.previousIndex, event.newIndex);
} else {
moveItemToNewContainer(
event.previousContainer.data,
event.newContainer.data,
event.previousIndex,
event.newIndex
);
}
}
enterPredicate(item: MdbDraggableDirective) {
return item.data % 2 !== 0;
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Disabled sorting
By setting sorting
input to false
you can disable sorting
in table.
Sorting available
Sorting not available
<div class="d-flex">
<div #firstContainer="mdbSortableContainer" mdbSortableContainer [containers]="[secondContainer]" [data]="itemsFirst" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Sorting available</h4>
<div mdbDraggable *ngFor="let item of itemsFirst" class="sortable-item">{{ item.name }}</div>
</div>
<div #secondContainer="mdbSortableContainer" mdbSortableContainer [containers]="[firstContainer]" [data]="itemsSecond" [sortingDisabled]="true" class="sortable-list" (itemDrop)="onDrop($event)">
<h4 class="text-center pt-2">Sorting disabled</h4>
<div mdbDraggable *ngFor="let item of itemsSecond" class="sortable-item">{{ item.name }}</div>
</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, moveItemToNewContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
itemsFirst = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' },
];
itemsSecond = [
{ name: 'Item 6' },
{ name: 'Item 7' },
];
onDrop(event: MdbDropEvent) {
if (event.previousContainer === event.newContainer) {
moveItemsInContainer(event.newContainer.data, event.previousIndex, event.newIndex);
} else {
moveItemToNewContainer(
event.previousContainer.data,
event.newContainer.data,
event.previousIndex,
event.newIndex
);
}
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Nested
To do
Done
<div
id="sortable-multi-1-1"
class="sortable-list d-flex align-items-start"
mdbSortableContainer
[data]="nestedContainers"
(itemDrop)="onDrop($event)"
>
<div
*ngFor="let container of nestedContainers"
class="sortable-list sortable-item-nested"
mdbSortableContainer
[id]="container.id"
[data]="container.data"
[containers]="getConnectedContainers(container.id)"
mdbDraggable
(itemDrop)="onDrop($event)"
>
<h4 class="text-center pt-2 drag-handler">{{ container.name }}</h4>
<div mdbDraggable *ngFor="let item of container.data" class="sortable-item">{{ item.name }}</div>
</div>
</div>
import { Component } from '@angular/core';
import { moveItemsInContainer, moveItemToNewContainer, MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
nestedContainers = [
{
id: 'nested-sortable-1',
name: 'To do',
data: [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' },
],
},
{
id: 'nested-sortable-2',
name: 'Done',
data: [{ name: 'Item 6' }, { name: 'Item 7' }, { name: 'Item 8' }, { name: 'Item 9' }],
},
];
getConnectedContainers(id: string) {
return this.nestedContainers.filter((container) => container.id !== id).map((container) => container.id);
}
onDrop(event: MdbDropEvent) {
if (event.previousContainer === event.newContainer) {
moveItemsInContainer(event.newContainer.data, event.previousIndex, event.newIndex);
} else {
moveItemToNewContainer(
event.previousContainer.data,
event.newContainer.data,
event.previousIndex,
event.newIndex
);
}
}
};
.sortable-list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: #fff;
border-radius: 4px;
}
.sortable-item {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
background: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
user-select: none;
}
.sortable-item:last-child {
border: none;
}
.draggable-helper {
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.21) !important;
}
Drag and drop - API
Installation
To install and configure the plugin follow our Plugins Installation Guide. Please remember to update all the plugin names and import paths. You can find all the necessary information in the Import section.
npm i git+https://oauth2:ACCESS_TOKEN@git.mdbootstrap.com/mdb/angular/mdb5/plugins/prd/drag-and-drop
Import
import { MdbDragAndDropModule } from 'mdb-angular-drag-and-drop';
…
@NgModule ({
...
imports: [MdbDragAndDropModule],
...
})
@import 'mdb-angular-drag-and-drop/scss/drag-and-drop.scss';
Inputs
MdbDraggableDirective
Name | Type | Default | Description |
---|---|---|---|
boundaryElement
|
HTMLElement | String | body |
Defines boundary container for dragged element |
copy
|
Boolean | false |
Defines if dragged element should be moved or copied to new container |
data
|
any | - |
Defines draggable element data |
delay
|
Number | 0 |
Defines how long will deley exist before element starts to drag |
disabled
|
Boolean | false |
Defines whether element is able to drag or not |
handle
|
HTMLElement | String | - |
Defines drag handler of the element. Note, handler has to be inside of the dragging element |
lockAxis
|
'x' | 'y' | null | null |
Defines whether 'x' or 'y' axis is blocked |
MdbSortableContainerDirective
Name | Type | Default | Description |
---|---|---|---|
containers
|
MdbSortableContainer | String | [] |
Defines list of connected containers |
enterPredicate
|
Function | () => true |
Defines function which check access between tables |
sortingDisabled
|
Boolean | false |
Defines whether list is able to sort or not |
Outputs
MdbDraggableDirective
Name | Type | Description |
---|---|---|
dragStart
|
EventEmitter<HTMLElement> | Emitted on drag start. |
dragEnd
|
EventEmitter<HTMLElement> | Emitted on drag end. |
<section class="border p-4 d-flex justify-content-center mb-4" style="height: 400px">
<div
mdbDraggable
(dragStart)="onDragStart($event)"
class="draggable-element shadow-1-strong"
>
<p>Drag me!</p>
</div>
</section>
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
onDragStart(target: HTMLElement) {
console.log('drag started:', target);
}
}
MdbSortableContainerDirective
Name | Type | Description |
---|---|---|
itemDrop
|
EventEmitter<MdbDropEvent> | Emitted on element drop in container |
<section class="border p-4 d-flex justify-content-center mb-4">
<div mdbSortableContainer class="sortable-list" (itemDrop)="onDrop($event)">
<div mdbDraggable class="sortable-item" *ngFor="let item of items">
{{ item.name }}
</div>
</div>
</section>
import { Component } from '@angular/core';
import { MdbDropEvent } from 'mdb-angular-drag-and-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' },
{ name: 'Item 4' },
{ name: 'Item 5' },
];
onDrop(event: MdbDropEvent) {
console.log('item dropped', event)
}
}
Advanced types
MdbDropEvent
interface MdbDropEvent {
item: MdbDraggableDirective;
previousContainer: MdbSortableContainerDirective;
newContainer: MdbSortableContainerDirective;
previousIndex: number;
newIndex: number;
}