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/guide/essentials/core-concepts.md.

Core concepts

Every setup, from one list to a full board, is made of the same four parts.

ConceptWhat it isDeclared with
DroppableA list that items can be dropped into, identified by an ID.vdndDroppable="id", or droppableId on <vdnd-sortable-list>
DraggableAn item that can be picked up, identified by an ID.[vdndDraggable]="item.id"
GroupA name linking draggables and droppables. Items move only between droppables of the same group.vdndGroup="name" on an ancestor element
PreviewThe element that follows the pointer during a drag.<vdnd-drag-preview />, placed once

Life of a drag

  1. The user presses on a draggable and moves past the drag threshold (5 px by default), or presses Space on a focused draggable.
  2. The dragged element is hidden with display: none. The preview appears under the pointer and an empty placeholder marks the drop position in the target list.
  3. As the pointer moves, the library works out which droppable is under it and at which index the item would land. Near the edges of a scrollable list it scrolls automatically.
  4. On release, the dragged draggable emits (dragEnd), whether the item was dropped or not. If it was dropped, the destination droppable then emits (drop) with the source and destination indexes. Both fire before the next render.
  5. Your handler updates the data. The library never changes your arrays.
onDrop(event: DropEvent): void {
  // Same list or across lists, keyed by droppable ID
  moveItem(event, { todo: this.todo, done: this.done });
}

See Handling drops for the event shape and the helper functions.

Rules that fail silently

Breaking any of these rules causes no build error. The list just does not drag, or drops items in the wrong place.

  1. Every draggable and droppable needs a group, even when there is only one list. Wrap them in vdndGroup, or set vdndDraggableGroup / vdndDroppableGroup (group on <vdnd-sortable-list>). Without a group, dragging is disabled and the only hint is a warning in the console in dev mode.
  2. Declare the item <ng-template> inside the vdndGroup element. Templates resolve injection where they are declared, not where they are rendered.
  3. The draggable ID must equal the list's item ID: what itemIdFn(item) returns, or the trackBy key for *vdndVirtualFor. IDs are strings, so convert numeric IDs the same way in both places.
  4. Draggable IDs must be unique across all lists, and droppable IDs must be unique on the page.
  5. Render <vdnd-drag-preview /> once. Without it, dragging works but nothing follows the pointer.
  6. Give every virtual list a height, with containerHeight or with CSS. A list without a height collapses to 0 px. To size <vdnd-sortable-list> with CSS, set the height on its inner vdnd-virtual-scroll from a global stylesheet.
  7. Put vdndDraggable on the root element of the item template. A wrapper around it would stay in the list during the drag and leave a gap.
  8. Bind (drop) on every list that can receive items. It fires on the destination only.
  9. With fixed heights, make every row exactly itemHeight pixels tall, borders and padding included. Otherwise the rows on screen drift away from the positions the list calculates. For rows of different heights, use dynamicItemHeight.

Troubleshooting maps common symptoms back to these rules.