The Problem

The Angular CDK drag-drop module provides powerful drag and drop functionality. However, items can escape their boundary containers, and scrolling behavior during drag operations can be broken, causing poor user experience.

Symptoms

  • Draggable items can be dragged outside their container
  • List does not auto-scroll when dragging near edges
  • Drop position is incorrect after scrolling
  • Items flicker or jump during drag

Real Error Scenario

html
<div class="scrollable-list">
  <div
    cdkDrag
    *ngFor="let item of items; trackBy: trackByFn"
    [cdkDragData]="item">
    {{ item.name }}
  </div>
</div>

Without proper configuration, items can be dragged outside the scrollable container, and the list does not auto-scroll.

How to Fix It

Fix 1: Constrain to Parent Container

html
<div class="scrollable-list" cdkDropList>
  <div
    cdkDrag
    [cdkDragBoundary]="'cdk-drop-list'"
    *ngFor="let item of items"
    [cdkDragData]="item">
    {{ item.name }}
  </div>
</div>
css
.scrollable-list {
  max-height: 400px;
  overflow-y: auto;
  position: relative;
}

Fix 2: Enable Auto-Scroll

html
<div
  cdkDropList
  cdkDropListAutoScroll
  [cdkDropListAutoScrollStep]="4"
  (cdkDropListDropped)="onDrop($event)">
  <div cdkDrag *ngFor="let item of items">
    {{ item.name }}
  </div>
</div>

Fix 3: Constrain Drag with cdkDragConstrainPosition

typescript
constrainPosition(dragRef, point) {
  const boundary = dragRef.element.nativeElement.parentElement.getBoundingClientRect();
  return {
    x: Math.max(boundary.left, Math.min(point.x, boundary.right)),
    y: Math.max(boundary.top, Math.min(point.y, boundary.bottom))
  };
}
html
<div
  cdkDrag
  [cdkDragConstrainPosition]="constrainPosition">
  {{ item.name }}
</div>

Fix 4: Handle Scroll Position During Drop

```typescript onDrop(event: CdkDragDrop<string[]>) { // Account for scroll position const scrollTop = this.scrollContainer.nativeElement.scrollTop;

moveItemInArray(this.items, event.previousIndex, event.currentIndex);

// Restore scroll position if needed this.scrollContainer.nativeElement.scrollTop = scrollTop; } ```

Fix 5: Virtual Scroll Integration

html
<cdk-virtual-scroll-viewport [itemSize]="50" class="scroll-viewport">
  <div cdkDropList (cdkDropListDropped)="onDrop($event)">
    <div
      cdkDrag
      *cdkVirtualFor="let item of items"
      [cdkDragData]="item">
      {{ item.name }}
    </div>
  </div>
</cdk-virtual-scroll-viewport>