Overview for drag-drop

The @angular/cdk/drag-drop module provides you with a way to easily and declaratively create drag-and-drop interfaces, with support for free dragging, sorting within a list, transferring items between lists, animations, touch devices, custom drag handles, previews, and placeholders, in addition to horizontal lists and locking along an axis.

Start by importing DragDropModule into the NgModule where you want to use drag-and-drop features. You can now add the cdkDrag directive to elements to make them draggable. When outside of a cdkDropList element, draggable elements can be freely moved around the page. You can add cdkDropList elements to constrain where elements may be dropped.

Basic Drag&Drop
Drag me around

Adding cdkDropList around a set of cdkDrag elements groups the draggables into a reorderable collection. Items will automatically rearrange as an element moves. Note that this will not update your data model; you can listen to the cdkDropListDropped event to update the data model once the user finishes dragging.

Drag&Drop sorting
Episode I - The Phantom Menace
Episode II - Attack of the Clones
Episode III - Revenge of the Sith
Episode IV - A New Hope
Episode V - The Empire Strikes Back
Episode VI - Return of the Jedi
Episode VII - The Force Awakens
Episode VIII - The Last Jedi
Episode IX – The Rise of Skywalker

The cdkDropList directive supports transferring dragged items between connected drop zones. You can connect one or more cdkDropList instances together by setting the cdkDropListConnectedTo property or by wrapping the elements in an element with the cdkDropListGroup attribute.

Drag&Drop connected sorting

To do

Get to work
Pick up groceries
Go home
Fall asleep

Done

Get up
Brush teeth
Take a shower
Check e-mail
Walk dog

Note that cdkDropListConnectedTo works both with a direct reference to another cdkDropList, or by referencing the id of another drop container:

<!-- This is valid -->
<div cdkDropList #listOne="cdkDropList" [cdkDropListConnectedTo]="[listTwo]"></div>
<div cdkDropList #listTwo="cdkDropList" [cdkDropListConnectedTo]="[listOne]"></div>

<!-- This is valid as well -->
<div cdkDropList id="list-one" [cdkDropListConnectedTo]="['list-two']"></div>
<div cdkDropList id="list-two" [cdkDropListConnectedTo]="['list-one']"></div>

If you have an unknown number of connected drop lists, you can use the cdkDropListGroup directive to set up the connection automatically. Note that any new cdkDropList that is added under a group will be connected to all other lists automatically.

<div cdkDropListGroup>
  <!-- All lists in here will be connected. -->
  @for (list of lists; track list) {
    <div cdkDropList></div>
  }
</div>
Drag&Drop connected sorting group

To do

Get to work
Pick up groceries
Go home
Fall asleep

Done

Get up
Brush teeth
Take a shower
Check e-mail
Walk dog

You can associate some arbitrary data with both cdkDrag and cdkDropList by setting cdkDragData or cdkDropListData, respectively. Events fired from both directives include this data, allowing you to easily identify the origin of the drag or drop interaction.

@for (list of lists; track list) {
  <div cdkDropList [cdkDropListData]="list" (cdkDropListDropped)="drop($event)">
    @for (item of list; track item) {
      <div cdkDrag [cdkDragData]="item"></div>
    }
  </div>
}

The cdkDrag and cdkDropList directive include only those styles strictly necessary for functionality. The application can then customize the elements by styling CSS classes added by the directives:

Selector Description
.cdk-drop-list Corresponds to the cdkDropList container.
.cdk-drag Corresponds to a cdkDrag instance.
.cdk-drag-disabled Class that is added to a disabled cdkDrag.
.cdk-drag-handle Class that is added to the host element of the cdkDragHandle directive.
.cdk-drag-preview This is the element that will be rendered next to the user's cursor as they're dragging an item in a sortable list. By default the element looks exactly like the element that is being dragged.
.cdk-drag-placeholder This is element that will be shown instead of the real element as it's being dragged inside a cdkDropList. By default this will look exactly like the element that is being sorted.
.cdk-drop-list-dragging A class that is added to cdkDropList while the user is dragging an item.
.cdk-drop-list-disabled A class that is added to cdkDropList when it is disabled.
.cdk-drop-list-receiving A class that is added to cdkDropList when it can receive an item that is being dragged inside a connected drop list.

The drag-and-drop module supports animations both while sorting an element inside a list, as well as animating it from the position that the user dropped it to its final place in the list. To set up your animations, you have to define a transition that targets the transform property. The following classes can be used for animations:

  • .cdk-drag - If you add a transition to this class, it'll animate as the user is sorting through a list.
  • .cdk-drag-animating - This class is added to a cdkDrag when the user has stopped dragging. If you add a transition to it, the CDK will animate the element from its drop position to the final position inside the cdkDropList container.

Example animations:

/* Animate items as they're being sorted. */
.cdk-drop-list-dragging .cdk-drag {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

/* Animate an item that has been dropped. */
.cdk-drag-animating {
  transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
}

By default, the user can drag the entire cdkDrag element to move it around. If you want to restrict the user to only be able to do so using a handle element, you can do it by adding the cdkDragHandle directive to an element inside of cdkDrag. Note that you can have as many cdkDragHandle elements as you want:

Drag&Drop with a handle
I can only be dragged using the handle

When a cdkDrag element is picked up, it will create a preview element visible while dragging. By default, this will be a clone of the original element positioned next to the user's cursor. This preview can be customized, though, by providing a custom template via *cdkDragPreview. Using the default configuration the custom preview won't match the size of the original dragged element, because the CDK doesn't make assumptions about the element's content. If you want the size to be matched, you can pass true to the matchSize input.

Note that the cloned element will remove its id attribute in order to avoid having multiple elements with the same id on the page. This will cause any CSS that targets that id not to be applied.

Drag&Drop custom preview
Episode I - The Phantom Menace
Episode II - Attack of the Clones
Episode III - Revenge of the Sith
Episode IV - A New Hope
Episode V - The Empire Strikes Back
Episode VI - Return of the Jedi
Episode VII - The Force Awakens
Episode VIII - The Last Jedi
Episode IX – The Rise of Skywalker

By default, the preview of a cdkDrag will be inserted into the <body> of the page in order to avoid issues with z-index and overflow: hidden. This may not be desireable in some cases, because the preview won't retain its inherited styles. You can control where the preview is inserted using the cdkDragPreviewContainer input on cdkDrag. The possible values are:

Value Description Advantages Disadvantages
global Default value. Preview is inserted into the <body> or the closest shadow root. Preview won't be affected by z-index or overflow: hidden. It also won't affect :nth-child selectors and flex layouts. Doesn't retain inherited styles.
parent Preview is inserted inside the parent of the item that is being dragged. Preview inherits the same styles as the dragged item. Preview may be clipped by overflow: hidden or be placed under other elements due to z-index. Furthermore, it can affect :nth-child selectors and some flex layouts.
ElementRef or HTMLElement Preview will be inserted into the specified element. Preview inherits styles from the specified container element. Preview may be clipped by overflow: hidden or be placed under other elements due to z-index. Furthermore, it can affect :nth-child selectors and some flex layouts.

While a cdkDrag element is being dragged, the CDK will create a placeholder element that will show where it will be placed when it's dropped. By default the placeholder is a clone of the element that is being dragged, however you can replace it with a custom one using the *cdkDragPlaceholder directive:

Drag&Drop custom placeholder
Episode I - The Phantom Menace
Episode II - Attack of the Clones
Episode III - Revenge of the Sith
Episode IV - A New Hope
Episode V - The Empire Strikes Back
Episode VI - Return of the Jedi
Episode VII - The Force Awakens
Episode VIII - The Last Jedi
Episode IX - The Rise of Skywalker

The cdkDropList directive assumes that lists are vertical by default. This can be changed by setting the cdkDropListOrientation property to horizontal.

Drag&Drop horizontal sorting
Bronze age
Iron age
Middle ages
Early modern period
Long nineteenth century

By default the cdkDropList sorts the items by moving them around using a CSS transform. This allows for the sorting to be animated which provides a better user experience, but comes with the drawback that it works only one direction: vertically or horizontally.

If you have a sortable list that needs to wrap, you can set cdkDropListOrientation="mixed" which will use a different strategy of sorting the elements that works by moving them in the DOM. It has the advantage of allowing the items to wrap to the next line, but it cannot animate the sorting action.

Drag&Drop horizontal wrapping list
Zero
One
Two
Three
Four
Five
Six
Seven
Eight
Nine

If you want to stop the user from being able to drag a cdkDrag element outside of another element, you can pass a CSS selector to the cdkDragBoundary attribute. The attribute works by accepting a selector and looking up the DOM until it finds an element that matches it. If a match is found, it'll be used as the boundary outside of which the element can't be dragged. cdkDragBoundary can also be used when cdkDrag is placed inside a cdkDropList.

Drag&Drop boundary
I can only be dragged within the dotted container

By default, cdkDrag allows free movement in all directions. To restrict dragging to a specific axis, you can set cdkDragLockAxis on cdkDrag or cdkDropListLockAxis on cdkDropList to either "x" or "y".

Drag&Drop position locking
I can only be dragged up/down
I can only be dragged left/right

If there's an element that you want to make draggable, but you don't have direct access to it, you can use the cdkDragRootElement attribute. The attribute works by accepting a selector and looking up the DOM until it finds an element that matches the selector. If an element is found, it'll become the element that is moved as the user is dragging. This is useful for cases like making a dialog draggable.

Drag&Drop with alternate root element

By default, all cdkDrag items from one container can be moved into another connected container. If you want more fine-grained control over which items can be dropped, you can use the cdkDropListEnterPredicate which will be called whenever an item is about to enter a new container. Depending on whether the predicate returns true or false, the item may or may not be allowed into the new container.

Drag&Drop enter predicate

Available numbers

1
2
3
4
5
6
7
8
9

Even numbers

10

If you want to disable dragging for a particular drag item, you can do so by setting the cdkDragDisabled input on a cdkDrag item. Furthermore, you can disable an entire list using the cdkDropListDisabled input on a cdkDropList or a particular handle via cdkDragHandleDisabled on cdkDragHandle.

Drag&Drop disabled
I can be dragged
I cannot be dragged
I can also be dragged

There are cases where draggable items can be dragged out of one list into another, however the user shouldn't be able to sort them within the source list. For these cases you can set the cdkDropListSortingDisabled input which will prevent the items in a cdkDropList from sorting, in addition to preserving the dragged item's initial position in the source list, if the user decides to return the item.

Drag&Drop disabled sorting

Available items

Carrots
Tomatoes
Onions
Apples
Avocados

Shopping basket

Oranges
Bananas
Cucumbers

By default as soon as the user puts their pointer down on a cdkDrag, the dragging sequence will be started. This might not be desirable in cases like fullscreen draggable elements on touch devices where the user might accidentally trigger a drag as they're scrolling the page. For cases like these you can delay the dragging sequence using the cdkDragStartDelay input which will wait for the user to hold down their pointer for the specified number of milliseconds before moving the element.

Delayed dragging
Dragging starts after one second

By default, standalone cdkDrag elements move from their normal DOM position only when manually moved by a user. The element's position can be explicitly set, however, via the cdkDragFreeDragPosition input. Applications commonly use this, for example, to restore a draggable's position after a user has navigated away and then returned.

Programmatically setting the free drag position

Drag me around

cdkDrag items can be sorted into any position inside of a cdkDropList by default. You can change this behavior by setting a cdkDropListSortPredicate. The predicate function will be called whenever an item is about to be moved into a new index. If the predicate returns true, the item will be moved into the new index, otherwise it will keep its current position.

Drag&Drop sort predicate
1
2
3
4
5
6
7
8

The CDK's drag&drop functionality can be integrated with different parts of Angular Material.

This example shows how you can set up a table which supports re-ordering of tabs.

Drag&Drop table
No. Name Weight Symbol Quantity of Element 1 Hydrogen 1.0079 H 1002 Helium 4.0026 He 1003 Lithium 6.941 Li 1004 Beryllium 9.0122 Be 1005 Boron 10.811 B 1006 Carbon 12.0107 C 1007 Nitrogen 14.0067 N 1008 Oxygen 15.9994 O 1009 Fluorine 18.9984 F 10010 Neon 20.1797 Ne 100

Example of how to add sorting support to a mat-tab-group.

Drag&Drop tabs

Content for One

Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quidem perspiciatis in delectus reprehenderit, molestias ullam nostrum odit, modi consequatur harum beatae? Sapiente voluptatibus illo natus assumenda hic quasi dolor et laborum veniam! Molestiae architecto nesciunt est quo nisi? Nostrum repellendus quibusdam laudantium? Optio architecto explicabo labore sapiente cum alias nobis!