Move Tasks with Drag and Drop
Move Tasks with Drag and Drop
The final interaction in this module is moving a task between columns. The browser already provides drag-and-drop events; React’s job is to connect those events to your task state.
1. Make the card draggable
On the task article, add:
<article
className="task"
draggable
onDragStart={() => onDragStart(task.id)}
>
The important value is the task id. The drop target does not need the whole task object.
2. Carry the id during the drag
Use the browser’s dataTransfer object:
function handleDragStart(event, taskId) {
event.dataTransfer.setData("text/plain", taskId);
}
Pass this handler from App through Column to TaskCard.
3. Accept the drop in a column
A column needs a drop handler. The browser’s default behavior does not allow a normal element to receive a drop unless you prevent it:
function handleDragOver(event) {
event.preventDefault();
}
Then read the task id on drop and update its status:
function handleDrop(event, nextStatus) {
event.preventDefault();
const taskId = event.dataTransfer.getData("text/plain");
setTasks((current) =>
current.map((task) =>
task.id === taskId
? { ...task, status: nextStatus }
: task
)
);
}
4. Highlight the drop zone
The user should be able to see where a task can be dropped. Add a small piece of local state to Column such as isDragOver.
When dragover fires, set it to true. When the drag leaves or the drop completes, set it back to false.
Use that state to add a class:
<section className={`column ${status} ${isDragOver ? "drag-over" : ""}`}>
The starter stylesheet already provides the visual .drag-over treatment, so you only need to connect the class to React state.
Checkpoint
Drag a task from one column to another. You should see the target column highlight while the task is over it, and the task should move after the drop.
Notice what actually changed: the task did not get copied into another list. Its status changed, and the existing rendering logic placed it in the new column.