For AI agents: the complete documentation index is available at https://gultyayev.github.io/ngx-virtual-dnd/llms.txt, the full documentation bundle is available at https://gultyayev.github.io/ngx-virtual-dnd/llms-full.txt, and this page is available as Markdown at https://gultyayev.github.io/ngx-virtual-dnd/index.md.
3.4Shift animations now run on the compositor

ngx-virtual-dnd

Drag and drop for virtual scrolling

Sortable lists and boards for Angular that stay fast with thousands of items. Only the visible rows are rendered, and drag and drop still works across all of them.

npm i ngx-virtual-dnd

Built for virtual lists

Hit-testing and drop positions are computed from geometry, not from sibling DOM nodes, so drops land correctly on rows that are not rendered.

Dynamic item heights

Rows are measured with ResizeObserver and cached by ID. Lookups use prefix sums and binary search.

Multiple lists

Move items between any lists in the same group, with edge auto-scroll while dragging.

Keyboard and touch

Space to pick up, arrow keys to move, Escape to cancel. Touch drags support a hold delay so lists still scroll.

Signals first

Standalone components and directives for Angular 21 and 22. Drop events plus small helpers update your signal-based state.

Guides for AI assistants

An installable agent skill and llms.txt give coding assistants the same guidance as these docs.

Quick look

A sortable list of 1,000 rows in one template

Only the rows on screen are in the DOM. Drops arrive as events, and a helper applies them to your signal.

  1. Install the package No providers and no global stylesheet to register.
  2. Put rows and lists in a group Declare the row template inside a vdndGroup element so every draggable finds its group.
  3. Apply the drop The library never changes your data. reorderItems() applies the move to your signal.

Read the quick start →

<div vdndGroup="tasks">
  <ng-template #taskTpl let-task>
    <div class="row" [vdndDraggable]="task.id">{{ task.title }}</div>
  </ng-template>

  <vdnd-sortable-list
    droppableId="backlog"
    [items]="tasks()"
    [itemHeight]="48"
    [containerHeight]="336"
    [itemIdFn]="taskId"
    [itemTemplate]="taskTpl"
    (drop)="onDrop($event)"
  />
</div>

<vdnd-drag-preview />