Overview
This guide walks you through creating a simple drag and drop interface using dnd-kit. You’ll learn the fundamental concepts of making elements draggable and droppable, and how to manage state when items are moved between containers.What You’ll Build
A basic drag and drop interface where you can:- Drag an item from its initial position
- Drop it into a designated drop zone
- See visual feedback when hovering over the drop zone
Installation
First, install the required packages:Implementation
The
DragDropProvider component wraps your application and provides the drag and drop context. This is required for all dnd-kit functionality.import { DragDropProvider } from '@dnd-kit/react';
function App() {
return (
<DragDropProvider>
{/* Your draggable and droppable components go here */}
</DragDropProvider>
);
}
Use the
useDraggable hook to make an element draggable. The hook requires a unique id and returns a ref that you attach to your element.import { useDraggable } from '@dnd-kit/react';
function Draggable({ id }: { id: string }) {
const { ref } = useDraggable({ id });
return (
<button ref={ref} className="btn">
Drag me
</button>
);
}
id must be unique across all draggable itemsref connects the hook to the DOM elementUse the
useDroppable hook to create drop zones. The hook provides an isDropTarget boolean that indicates when a draggable item is over the drop zone.import { useDroppable } from '@dnd-kit/react';
function Droppable({ id, children }: { id: string; children?: React.ReactNode }) {
const { ref, isDropTarget } = useDroppable({ id });
return (
<div
ref={ref}
className={isDropTarget ? "droppable active" : "droppable"}
>
{children}
</div>
);
}
isDropTarget becomes true when a draggable is hovering over this drop zonechildren prop allows you to render content inside the drop zoneimport { useState } from 'react';
import { DragDropProvider, useDraggable, useDroppable } from '@dnd-kit/react';
function App() {
const [parent, setParent] = useState<string | undefined>(undefined);
const draggable = <Draggable id="draggable" />;
return (
<DragDropProvider
onDragEnd={(event) => {
if (event.canceled) return;
setParent(event.operation.target?.id as string);
}}
>
<section className="drop-layout">
{parent == null ? draggable : null}
<Droppable id="droppable">
{parent === 'droppable' ? draggable : null}
</Droppable>
</section>
</DragDropProvider>
);
}
Complete Example
Here’s the full working code:Styling
Add basic CSS to make the interface visually clear:Key Takeaways
- DragDropProvider wraps your app and provides drag and drop context
- useDraggable makes elements draggable by providing a ref
- useDroppable creates drop zones with visual feedback via
isDropTarget - onDragEnd event handler updates state when drag operations complete
- Check
event.canceledto handle cancelled drag operations - Use
event.operation.target?.idto identify where the item was dropped
Next Steps
- Learn about Multiple Containers for more complex layouts
- Explore Nested Contexts for advanced use cases