Guides

Feedback

Configure drag feedback, clone overlays, drop animations, and troubleshoot common issues like duplicate items in React.

Overview

The Feedback plugin manages visual feedback during drag operations. It is included by default and handles element promotion to the browser’s top layer and drop animations.

This guide covers common React patterns and troubleshooting.

Configuring feedback globally

To configure feedback for all draggable elements, pass a plugins function to DragDropProvider:

import {DragDropProvider} from '@dnd-kit/react';
import {Feedback} from '@dnd-kit/dom';

function App() {
  return (
    <DragDropProvider
      plugins={(defaults) => [
        ...defaults,
        Feedback.configure({dropAnimation: null}),
      ]}
    >
      {/* All draggable elements will have no drop animation */}
    </DragDropProvider>
  );
}

Use the function form (defaults) => [...] to extend the default plugins rather than replacing them. Passing a plain array replaces all default plugins, which may disable expected behavior like auto-scrolling and accessibility.

Per-draggable feedback

Configure feedback on individual elements via the plugins option in useDraggable or useSortable:

import {useDraggable} from '@dnd-kit/react';
import {Feedback} from '@dnd-kit/dom';

function CloneDraggable({id}: {id: string}) {
  const {ref} = useDraggable({
    id,
    plugins: [
      Feedback.configure({
        feedback: 'clone',
      }),
    ],
  });

  return <div ref={ref}>Drag me (clone stays behind)</div>;
}

Feedback modes

The feedback option controls how the element behaves during drag:

ModeBehavior
'default'The element is promoted to the top layer and moves with the pointer
'clone'A clone of the element stays in its original position while the original moves
'move'The element moves without top layer promotion or a placeholder
'none'No visual feedback from the Feedback plugin. Use this when rendering a custom DragOverlay

Drop animations

Disabling the drop animation

Feedback.configure({dropAnimation: null})

Customizing the drop animation

Feedback.configure({
  dropAnimation: {
    duration: 300,   // milliseconds (default: 250)
    easing: 'ease',  // CSS easing (default: 'ease')
  },
})

Custom animation function

For full control, provide a function that returns a Promise:

Feedback.configure({
  dropAnimation: async ({element, translate}) => {
    await element.animate(
      [{transform: `translate3d(${translate.x}px, ${translate.y}px, 0)`}, {transform: 'translate3d(0, 0, 0)'}],
      {duration: 200, easing: 'ease-out'}
    ).finished;
  },
})

Troubleshooting

Duplicate items after data refetch

When using sortable lists with React Query or other data fetching libraries, you may see duplicate items after a refetch. This happens because the OptimisticSortingPlugin has moved DOM elements during the drag, and the refetched data renders new elements in the updated positions.

See Integration with external state for how to solve this by deferring state sync until the drag is complete.

Double animation or snap on drop

If items snap into position twice after dropping, your state update is likely conflicting with the drop animation. The Feedback plugin animates the element back, then your state update triggers a re-render that moves it again.

To fix this, disable the drop animation:

Feedback.configure({dropAnimation: null})

Or ensure your state update matches the final position by using the move helper from @dnd-kit/helpers in onDragEnd, which correctly reconciles the optimistic position with your state.

For the complete API reference including rootElement and keyboardTransition options, see the core Feedback plugin documentation.