or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

accessibility.mdaccordion.mdcollections-data.mddialogs.mddrag-drop.mdindex.mdlistbox.mdmenus.mdobservers.mdoverlays.mdplatform-utilities.mdportals.mdscrolling.mdtesting.mdtext-fields.md
tile.json

drag-drop.mddocs/

Drag and Drop

The Angular CDK Drag and Drop module provides comprehensive functionality for creating draggable elements and drop zones with support for sorting, transferring between lists, custom drag previews, and accessibility features.

Capabilities

Drag and Drop Service

The core service for creating draggable elements and drop zones programmatically.

/**
 * Service for creating drag and drop functionality
 */
class DragDrop {
  /**
   * Create a draggable element reference
   * @param element - Element to make draggable
   * @param config - Optional drag configuration
   * @returns DragRef for managing the drag behavior
   */
  createDrag<T = any>(
    element: ElementRef<HTMLElement> | HTMLElement, 
    config?: DragRefConfig
  ): DragRef<T>;
  
  /**
   * Create a drop list reference
   * @param element - Element to make a drop zone
   * @returns DropListRef for managing drop behavior
   */
  createDropList<T = any>(
    element: ElementRef<HTMLElement> | HTMLElement
  ): DropListRef<T>;
}

Drag Reference

Reference to a draggable element for controlling drag behavior.

/**
 * Reference to a draggable element
 * @template T Type of data associated with the draggable element
 */
class DragRef<T = any> {
  /**
   * Data associated with this draggable element
   */
  data: T;
  
  /**
   * Whether dragging is disabled
   */
  disabled: boolean;
  
  /**
   * Axis to lock dragging to
   */
  lockAxis: 'x' | 'y' | null;
  
  /**
   * Observable that emits when the element is being moved
   */
  moved: Observable<{
    source: DragRef;
    pointerPosition: {x: number; y: number};
    event: MouseEvent | TouchEvent;
    delta: {x: number; y: number};
    distance: {x: number; y: number};
  }>;
  
  /**
   * Observable that emits when dragging starts
   */
  started: Observable<{
    source: DragRef;
    event: MouseEvent | TouchEvent;
  }>;
  
  /**
   * Observable that emits when the element is released
   */
  released: Observable<{
    source: DragRef;
    event: MouseEvent | TouchEvent;
  }>;
  
  /**
   * Observable that emits when dragging ends
   */
  ended: Observable<{
    source: DragRef;
    distance: {x: number; y: number};
    dropPoint: {x: number; y: number};
    event: MouseEvent | TouchEvent;
  }>;
  
  /**
   * Observable that emits when the element enters a drop zone
   */
  entered: Observable<{
    container: DropListRef;
    item: DragRef;
    currentIndex: number;
  }>;
  
  /**
   * Observable that emits when the element exits a drop zone
   */
  exited: Observable<{
    container: DropListRef;
    item: DragRef;
  }>;
  
  /**
   * Observable that emits when the element is dropped
   */
  dropped: Observable<{
    previousIndex: number;
    currentIndex: number;
    item: DragRef;
    container: DropListRef;
    previousContainer: DropListRef;
    distance: {x: number; y: number};
    dropPoint: {x: number; y: number};
    event: MouseEvent | TouchEvent;
  }>;
  
  /**
   * Dispose of the drag reference and clean up
   */
  dispose(): void;
  
  /**
   * Get the current position of the drag element
   * @returns Current position
   */
  getFreeDragPosition(): {x: number; y: number};
  
  /**
   * Set the current position of the drag element
   * @param position - Position to set
   */
  setFreeDragPosition(position: {x: number; y: number}): void;
  
  /**
   * Reset the drag element to its original position
   */
  reset(): void;
}

Drop List Reference

Reference to a drop zone for managing drop behavior.

/**
 * Reference to a drop list/zone
 * @template T Type of data associated with the drop list
 */
class DropListRef<T = any> {
  /**
   * Data associated with this drop list
   */
  data: T;
  
  /**
   * Whether dropping is disabled
   */
  disabled: boolean;
  
  /**
   * Axis to lock dropping to
   */
  lockAxis: 'x' | 'y' | null;
  
  /**
   * Whether sorting within this list is disabled
   */
  sortingDisabled: boolean;
  
  /**
   * Orientation of the drop list
   */
  orientation: 'horizontal' | 'vertical';
  
  /**
   * Observable that emits when items are sorted within the list
   */
  sorted: Observable<{
    previousIndex: number;
    currentIndex: number;
    container: DropListRef;
    item: DragRef;
  }>;
  
  /**
   * Observable that emits when an item is dropped into this list
   */
  dropped: Observable<{
    previousIndex: number;
    currentIndex: number;
    item: DragRef;
    container: DropListRef;
    previousContainer: DropListRef;
    isPointerOverContainer: boolean;
    distance: {x: number; y: number};
    dropPoint: {x: number; y: number};
  }>;
  
  /**
   * Observable that emits when an item enters this list
   */
  entered: Observable<{
    container: DropListRef;
    item: DragRef;
    currentIndex: number;
  }>;
  
  /**
   * Observable that emits when an item exits this list
   */
  exited: Observable<{
    container: DropListRef;
    item: DragRef;
  }>;
  
  /**
   * Set the draggable items in this list
   * @param items - Array of DragRef items
   */
  withItems(items: DragRef[]): this;
  
  /**
   * Connect this drop list to other drop lists for transferring items
   * @param connectedTo - Array of connected drop lists
   */
  connectedTo(connectedTo: DropListRef[]): this;
  
  /**
   * Dispose of the drop list reference and clean up
   */
  dispose(): void;
}

Drag Directives

Directives for creating draggable elements declaratively.

/**
 * Directive that makes an element draggable
 */
@Directive({
  selector: '[cdkDrag]'
})
class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
  /**
   * Data associated with the draggable element
   */
  @Input('cdkDragData') data: T;
  
  /**
   * Whether dragging is disabled
   */
  @Input('cdkDragDisabled') disabled: boolean;
  
  /**
   * Axis to lock dragging to
   */
  @Input('cdkDragLockAxis') lockAxis: 'x' | 'y';
  
  /**
   * Root draggable element selector
   */
  @Input('cdkDragRootElement') rootElementSelector: string;
  
  /**
   * Boundary element to constrain dragging
   */
  @Input('cdkDragBoundary') boundaryElement: string | ElementRef<HTMLElement> | HTMLElement;
  
  /**
   * Starting position for free drag
   */
  @Input('cdkDragFreeDragPosition') freeDragPosition: {x: number; y: number};
  
  /**
   * Event emitted when dragging starts
   */
  @Output('cdkDragStarted') started: EventEmitter<CdkDragStart<T>>;
  
  /**
   * Event emitted when the element is released
   */
  @Output('cdkDragReleased') released: EventEmitter<CdkDragRelease<T>>;
  
  /**
   * Event emitted when dragging ends
   */
  @Output('cdkDragEnded') ended: EventEmitter<CdkDragEnd<T>>;
  
  /**
   * Event emitted when the element enters a drop zone
   */
  @Output('cdkDragEntered') entered: EventEmitter<CdkDragEnter<T>>;
  
  /**
   * Event emitted when the element exits a drop zone
   */
  @Output('cdkDragExited') exited: EventEmitter<CdkDragExit<T>>;
  
  /**
   * Event emitted when the element is dropped
   */
  @Output('cdkDragDropped') dropped: EventEmitter<CdkDragDrop<T>>;
  
  /**
   * Event emitted when the element is moved
   */
  @Output('cdkDragMoved') moved: EventEmitter<CdkDragMove<T>>;
  
  /**
   * Get the drag reference
   */
  dragRef: DragRef<T>;
  
  /**
   * Get the current position (for free drag)
   * @returns Current position
   */
  getFreeDragPosition(): {x: number; y: number};
  
  /**
   * Reset the element to its original position
   */
  reset(): void;
}

/**
 * Directive that makes an element a drop zone
 */
@Directive({
  selector: '[cdkDropList], cdk-drop-list'
})
class CdkDropList<T = any> implements OnDestroy {
  /**
   * Data associated with the drop list
   */
  @Input('cdkDropListData') data: T;
  
  /**
   * Whether dropping is disabled
   */
  @Input('cdkDropListDisabled') disabled: boolean;
  
  /**
   * Axis to lock dropping to
   */
  @Input('cdkDropListLockAxis') lockAxis: 'x' | 'y';
  
  /**
   * Whether sorting is disabled
   */
  @Input('cdkDropListSortingDisabled') sortingDisabled: boolean;
  
  /**
   * Orientation of the drop list
   */
  @Input('cdkDropListOrientation') orientation: 'horizontal' | 'vertical';
  
  /**
   * CSS class to apply when an item is being dragged over
   */
  @Input('cdkDropListEnterPredicate') enterPredicate: (drag: CdkDrag, drop: CdkDropList) => boolean;
  
  /**
   * Connected drop lists for transferring items
   */
  @Input('cdkDropListConnectedTo') connectedTo: (CdkDropList | string)[] | CdkDropList | string;
  
  /**
   * Event emitted when an item is dropped
   */
  @Output('cdkDropListDropped') dropped: EventEmitter<CdkDragDrop<T, any>>;
  
  /**
   * Event emitted when an item enters the list
   */
  @Output('cdkDropListEntered') entered: EventEmitter<CdkDragEnter<T>>;
  
  /**
   * Event emitted when an item exits the list
   */
  @Output('cdkDropListExited') exited: EventEmitter<CdkDragExit<T>>;
  
  /**
   * Event emitted when items are sorted within the list
   */
  @Output('cdkDropListSorted') sorted: EventEmitter<CdkDragSortEvent<T>>;
  
  /**
   * Get the drop list reference
   */
  dropListRef: DropListRef<T>;
}

Drag Utilities

Additional directives for customizing drag behavior.

/**
 * Directive for creating a drag handle
 */
@Directive({
  selector: '[cdkDragHandle]'
})
class CdkDragHandle {
  /**
   * Whether the handle is disabled
   */
  @Input('cdkDragHandleDisabled') disabled: boolean;
}

/**
 * Directive for customizing the drag preview
 */
@Directive({
  selector: 'ng-template[cdkDragPreview]'
})
class CdkDragPreview<T = any> {
  /**
   * Data context for the preview template
   */
  data: T;
  
  /**
   * Whether to match the size of the dragged element
   */
  @Input() matchSize: boolean;
}

/**
 * Directive for customizing the drag placeholder
 */
@Directive({
  selector: 'ng-template[cdkDragPlaceholder]'
})
class CdkDragPlaceholder<T = any> {
  /**
   * Data context for the placeholder template
   */
  data: T;
}

Event Interfaces

Type definitions for drag and drop events.

/**
 * Event emitted when an item is dropped
 */
interface CdkDragDrop<T, O = T> {
  /** Index of the item when dragging started */
  previousIndex: number;
  
  /** Current index of the item */
  currentIndex: number;
  
  /** Item that was dropped */
  item: CdkDrag<T>;
  
  /** Container into which the item was dropped */
  container: CdkDropList<O>;
  
  /** Container from which the item was picked up */
  previousContainer: CdkDropList<T>;
  
  /** Whether the user's pointer was over the container when the item was dropped */
  isPointerOverContainer: boolean;
  
  /** Distance traveled by the pointer */
  distance: {x: number; y: number};
  
  /** Position where the item was dropped */
  dropPoint: {x: number; y: number};
  
  /** Native event that caused the drop */
  event: MouseEvent | TouchEvent;
}

/**
 * Event emitted when dragging starts
 */
interface CdkDragStart<T = any> {
  /** Item that started being dragged */
  source: CdkDrag<T>;
  
  /** Native event that started the drag */
  event: MouseEvent | TouchEvent;
}

/**
 * Event emitted when dragging ends
 */
interface CdkDragEnd<T = any> {
  /** Item that was being dragged */
  source: CdkDrag<T>;
  
  /** Distance traveled by the pointer */
  distance: {x: number; y: number};
  
  /** Position where the item ended up */
  dropPoint: {x: number; y: number};
  
  /** Native event that ended the drag */
  event: MouseEvent | TouchEvent;
}

/**
 * Event emitted when an item enters a drop zone
 */
interface CdkDragEnter<T = any, I = T> {
  /** Container that was entered */
  container: CdkDropList<T>;
  
  /** Item that entered the container */
  item: CdkDrag<I>;
  
  /** Index of the item in the container */
  currentIndex: number;
}

/**
 * Event emitted when an item exits a drop zone
 */
interface CdkDragExit<T = any, I = T> {
  /** Container that was exited */
  container: CdkDropList<T>;
  
  /** Item that exited the container */
  item: CdkDrag<I>;
}

/**
 * Event emitted when items are sorted within a list
 */
interface CdkDragSortEvent<T = any, I = T> {
  /** Index of the item when sorting started */
  previousIndex: number;
  
  /** Current index of the item */
  currentIndex: number;
  
  /** Container where sorting occurred */
  container: CdkDropList<T>;
  
  /** Item that was sorted */
  item: CdkDrag<I>;
}

/**
 * Event emitted when an item is being moved
 */
interface CdkDragMove<T = any> {
  /** Item being moved */
  source: CdkDrag<T>;
  
  /** Current pointer position */
  pointerPosition: {x: number; y: number};
  
  /** Native event causing the move */
  event: MouseEvent | TouchEvent;
  
  /** Distance moved since last event */
  delta: {x: number; y: number};
  
  /** Total distance moved since drag started */
  distance: {x: number; y: number};
}

/**
 * Event emitted when a drag element is released
 */
interface CdkDragRelease<T = any> {
  /** Item that was released */
  source: CdkDrag<T>;
  
  /** Native event that caused the release */
  event: MouseEvent | TouchEvent;
}

Utility Functions

Helper functions for manipulating arrays during drag and drop operations.

/**
 * Move an item from one index to another within the same array
 * @param array - Array to modify
 * @param fromIndex - Starting index
 * @param toIndex - Ending index
 */
function moveItemInArray<T>(array: T[], fromIndex: number, toIndex: number): void;

/**
 * Transfer an item from one array to another
 * @param currentArray - Source array
 * @param targetArray - Target array
 * @param currentIndex - Index in source array
 * @param targetIndex - Index in target array
 */
function transferArrayItem<T>(
  currentArray: T[],
  targetArray: T[],
  currentIndex: number,
  targetIndex: number
): void;

/**
 * Copy an item from one array to another
 * @param currentArray - Source array
 * @param targetArray - Target array
 * @param currentIndex - Index in source array
 * @param targetIndex - Index in target array
 */
function copyArrayItem<T>(
  currentArray: T[],
  targetArray: T[],
  currentIndex: number,
  targetIndex: number
): void;

Configuration

Configuration interfaces for drag behavior.

/**
 * Configuration for drag references
 */
interface DragRefConfig {
  /** Axis to lock dragging to */
  lockAxis?: 'x' | 'y';
  
  /** Whether to start dragging after a long press */
  longPressDelay?: number;
  
  /** Distance in pixels before drag starts */
  dragStartThreshold?: number;
  
  /** Position constraints */
  constrainPosition?: (point: Point, dragRef: DragRef) => Point;
  
  /** Custom preview element */
  previewClass?: string | string[];
  
  /** Boundary element */
  boundaryElement?: string | ElementRef<HTMLElement> | HTMLElement;
  
  /** Root element selector */
  rootElementSelector?: string;
  
  /** Preview container */
  previewContainer?: 'global' | 'parent' | ElementRef<HTMLElement> | HTMLElement;
}

/**
 * Point interface for coordinates
 */
interface Point {
  x: number;
  y: number;
}

Module

/**
 * Angular module that includes all drag and drop functionality
 */
@NgModule({
  declarations: [
    CdkDropList,
    CdkDrag,
    CdkDragHandle,
    CdkDragPreview,
    CdkDragPlaceholder
  ],
  exports: [
    CdkDropList,
    CdkDrag,
    CdkDragHandle,
    CdkDragPreview,
    CdkDragPlaceholder
  ]
})
class DragDropModule {}

Usage Patterns

Simple Sortable List

<div cdkDropList (cdkDropListDropped)="drop($event)">
  <div *ngFor="let item of items" cdkDrag>
    {{ item }}
  </div>
</div>
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';

export class SortableListComponent {
  items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.items, event.previousIndex, event.currentIndex);
  }
}

Transfer Between Lists

<div class="container">
  <div 
    cdkDropList 
    #todoList="cdkDropList"
    [cdkDropListData]="todo"
    [cdkDropListConnectedTo]="[doneList]"
    (cdkDropListDropped)="drop($event)">
    <div *ngFor="let item of todo" cdkDrag>{{ item }}</div>
  </div>

  <div 
    cdkDropList 
    #doneList="cdkDropList"
    [cdkDropListData]="done"
    [cdkDropListConnectedTo]="[todoList]"
    (cdkDropListDropped)="drop($event)">
    <div *ngFor="let item of done" cdkDrag>{{ item }}</div>
  </div>
</div>
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';

export class TransferListComponent {
  todo = ['Task 1', 'Task 2', 'Task 3'];
  done = ['Completed Task'];

  drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
  }
}