Guides
Migration guide
A comprehensive guide to migrate from `@dnd-kit/core` to `@dnd-kit/react`
Update dependencies
Update your package.json and install the new packages:
"dependencies": {
"@dnd-kit/core": "^x.x.x",
"@dnd-kit/sortable": "^x.x.x",
"@dnd-kit/utilities": "^x.x.x",
"@dnd-kit/react": "^x.x.x",
"@dnd-kit/helpers": "^x.x.x",
}After updating your package.json, install the new dependencies with your package manager of choice.
Migrate context provider
Update your context provider. The new DragDropProvider replaces the legacy DndContext:
import {DndContext} from '@dnd-kit/core';
function App() {
return (
<DndContext
onDragStart={({active}) => {
console.log(`Started dragging ${active.id}`);
}}
onDragEnd={({active, over}) => {
if (over) {
console.log(`Dropped ${active.id} over ${over.id}`);
}
}}
onDragCancel={({active}) => {
console.log(`Cancelled dragging ${active.id}`);
}}
>
<YourComponents />
</DndContext>
);
}import {DragDropProvider} from '@dnd-kit/react';
function App() {
return (
<DragDropProvider
onDragStart={(event, manager) => {
const {operation} = event;
console.log(`Started dragging ${operation.source.id}`);
}}
onDragEnd={(event, manager) => {
const {operation, canceled} = event;
const {source, target} = operation;
if (canceled) {
// Replaces onDragCancel
console.log(`Cancelled dragging ${source.id}`);
return;
}
if (target) {
console.log(`Dropped ${source.id} over ${target.id}`);
// Access rich data
console.log('Source data:', source.data);
console.log('Drop position:', operation.position.current);
}
}}
>
<YourComponents />
</DragDropProvider>
);
}The new provider gives you access to the manager instance in event handlers, enabling more advanced control over the drag and drop system.
Update draggable components
Update your draggable components using the new useDraggable hook:
function DraggableItem({id}) {
const {
attributes,
listeners,
setNodeRef,
transform
} = useDraggable({
id
});
return (
<div
ref={setNodeRef}
{...listeners}
{...attributes}
style={{
transform: CSS.Transform.toString(transform)
}}
>
Item {id}
</div>
);
}function DraggableItem({id}) {
const draggable = useDraggable({
id,
});
return (
<div
ref={draggable.ref}
className={isDragging ? 'dragging' : ''}
>
Item {id}
</div>
);
}Update droppable components
Update your droppable components using the new useDroppable hook:
function Dropzone() {
const {setNodeRef, isOver} = useDroppable({
id: 'drop-zone'
});
return (
<div
ref={setNodeRef}
style={{
background: isOver ? 'lightblue' : 'white'
}}
>
Drop here
</div>
);
}function Dropzone() {
const droppable = useDroppable({
id: 'drop-zone'
});
return (
<div
ref={droppable.ref}
style={{
background: droppable.isDropTarget ? 'green' : 'white'
}}
>
Drop here
</div>
);
}Update drag overlay
The DragOverlay component has been simplified:
function App() {
const [activeId, setActiveId] = useState(null);
return (
<DndContext
onDragStart={() => setActiveId('item')}
onDragEnd={() => setActiveId(null)}
>
<Draggable id="item" />
<DragOverlay>
{activeId ? <Item id={activeId} /> : null}
</DragOverlay>
</DndContext>
);
}function App() {
return (
<DragDropProvider>
<Draggable id="item" />
<DragOverlay>
{source => (
<Item id={source.id} />
)}
</DragOverlay>
</DragDropProvider>
);
}Only render the DragOverlay component once per DragDropProvider. The hooks have no effect when used within the overlay.
Migrate sortable components
Update your sortable components using the new useSortable hook:
import {useSortable} from '@dnd-kit/sortable';
function SortableItem({id, index}) {
const {
attributes,
listeners,
setNodeRef,
transform,
transition
} = useSortable({
id,
index
});
return (
<div
ref={setNodeRef}
{...attributes}
{...listeners}
style={{
transform: CSS.Transform.toString(transform),
transition
}}
>
Item {id}
</div>
);
}import {useSortable} from '@dnd-kit/react/sortable';
function SortableItem({id, index}) {
const sortable = useSortable({
id,
index
});
return (
<div
ref={sortable.ref}
className={sortable.isDragging ? 'dragging' : undefined}
>
Item {id}
</div>
);
}Use the array manipulation helpers from @dnd-kit/helpers to handle reordering.
API reference
A quick lookup for common legacy APIs and their new equivalents, organized by category.
Context & Provider
Legacy (@dnd-kit/core) | New (@dnd-kit/react) |
|---|---|
DndContext | DragDropProvider |
Events
| Legacy | New |
|---|---|
active | event.operation.source |
over | event.operation.target |
active.id | event.operation.source.id |
onDragCancel | Check event.canceled inside onDragEnd |
Sensors
The legacy MouseSensor and TouchSensor have been merged into a single PointerSensor that handles mouse, touch, and pen input via the native Pointer Events API. You can still apply different behavior per input type by passing a function to activationConstraints and branching on event.pointerType ('mouse', 'touch', or 'pen'):
import {DragDropProvider} from '@dnd-kit/react';
import {PointerSensor, PointerActivationConstraints} from '@dnd-kit/dom';
<DragDropProvider
sensors={(defaults) => [
...defaults.filter((sensor) => sensor !== PointerSensor),
PointerSensor.configure({
activationConstraints(event, source) {
if (event.pointerType === 'touch') {
return [
new PointerActivationConstraints.Delay({value: 500, tolerance: {x: 5, y: 5}}),
];
}
return [new PointerActivationConstraints.Distance({value: 8})];
},
}),
]}
>
{/* ... */}
</DragDropProvider>If you don’t configure it, the default already differentiates pointer types — see the PointerSensor docs for the full default behavior.
Legacy (@dnd-kit/core) | New (@dnd-kit/dom) |
|---|---|
useSensor / useSensors | Built-in by default. Customize via the sensors prop on DragDropProvider |
MouseSensor | PointerSensor from @dnd-kit/dom |
TouchSensor | PointerSensor from @dnd-kit/dom |
PointerSensor | PointerSensor from @dnd-kit/dom |
KeyboardSensor | KeyboardSensor from @dnd-kit/dom |
Collision detection
| Legacy | New |
|---|---|
collisionDetection prop on DndContext | collisionDetector option on useDroppable / useSortable |
pointerWithin | pointerIntersection from @dnd-kit/collision |
closestCenter | closestCenter from @dnd-kit/collision |
closestCorners | closestCorners from @dnd-kit/collision |
Modifiers
See the React modifiers guide for usage examples.
| Legacy | New |
|---|---|
restrictToParentElement | RestrictToElement from @dnd-kit/dom/modifiers |
restrictToWindowEdges | RestrictToWindow from @dnd-kit/dom/modifiers |
restrictToVerticalAxis | RestrictToVerticalAxis from @dnd-kit/abstract/modifiers |
restrictToHorizontalAxis | RestrictToHorizontalAxis from @dnd-kit/abstract/modifiers |
createSnapModifier | SnapModifier from @dnd-kit/abstract/modifiers |
Sortable
SortableContext is no longer needed. Sortable items register and coordinate with the DragDropProvider automatically when you use useSortable — there’s no wrapping context to configure. Use the type and accept options on useSortable to control which items can be sorted together.
See the sortable state management guide for usage examples.
| Legacy | New |
|---|---|
SortableContext | No longer needed — see note above |
arrayMove | move from @dnd-kit/helpers |
verticalListSortingStrategy | Not needed — handled automatically |
horizontalListSortingStrategy | Not needed — handled automatically |
rectSortingStrategy | Not needed — handled automatically |
Next steps
Build beautiful drag and drop interfaces in minutes with the new dnd kit
Use the move helper from @dnd-kit/helpers or manage state manually
Restrict movement to an element, axis, or snap to a grid in React
Configure drag feedback, clone overlays, and drop animations in React