Animations and haptics
By default, rows displaced by the placeholder jump to their new position, and the preview disappears on drop. Provide VDND_ANIMATION_CONFIG to make rows slide and the dropped item glide into its slot instead. For feedback on every step, such as a haptic tick, listen to (placeholderMove).
Shift animation
The animation is opt-in. Provide the config app-wide, or in a component's providers to animate only the lists in that subtree:
- The slide animates the
translateCSS property, so it runs on the compositor. It works with virtual scrolling and with dynamic heights. - It is skipped when the user has turned on reduced motion (
prefers-reduced-motion: reduce). - If the placeholder moves again mid-slide, rows continue from where they currently are.
- Drop positions are calculated from geometry, so a row that is still sliding never changes where an item lands.
- Rows also slide on drop or cancel. After a drop they usually already sit in their final slots, so a slide in progress simply finishes. After a cancel, displaced rows slide back.
- Your own
transformon rows is kept: the slide moves the row as a whole, and your rotation or scale does not distort the slide. If you settranslateon rows yourself, the slide is added to it, but then it runs on the main thread instead of the compositor, so prefertransformfor your own offsets. Atranslateyou change while a row is sliding applies once the slide ends.
The config is read each time an animation starts, so a getter can switch it at runtime, for example from a user setting:
Drop animation
With the same config, releasing an item no longer makes the preview vanish. The preview glides from where you let go onto the item's final position, then disappears. The real item stays invisible until the preview lands on it, so it is never shown twice. A cancelled drag (Escape) glides back to where the item started.
- It is purely visual.
dropanddragEndfire right away, and the list is already in its new order while the preview travels. - The preview lands on the item as it is rendered after your
(drop)handler. Commit the move in the handler (for example withmoveItem()orreorderItems()). If you commit later, for example after a server call, the preview glides back to the item's old slot. - If the item is not rendered, or is scrolled out of its list's view, the preview fades out where it was released.
- Starting a new drag ends the animation at once.
- While it plays, the preview box has the class
vdnd-drag-preview-dropping. - It is skipped under reduced motion, like the shift animation. Set
dropDuration: 0to keep only the shift animation.
Where it applies
Rows animate in <vdnd-sortable-list>, <vdnd-virtual-scroll> and every *vdndVirtualFor list, including those inside <vdnd-virtual-viewport> and <vdnd-virtual-content>.
Do not add your own CSS transition on the rows' transform, translate or top to get this effect. Rows are repositioned by layout (or by an inline top in a *vdndVirtualFor placed directly in a vdndScrollable), and a transition on any of them competes with the built-in slide.
Placeholder move events
vdndDroppable and <vdnd-sortable-list> emit placeholderMove each time the placeholder moves within that list, which is every time rows are displaced:
The event fires when the placeholder enters the list and on every move inside it. It does not fire for the initial pick-up or when the placeholder leaves the list. currentIndex is where the item would land if it were dropped now, so it also suits screen reader announcements. See PlaceholderMoveEvent for every field.
Keep the handler cheap, and bind it only where you use it: each event runs change detection for your component and its ancestors (see Performance).