CodingNic

Task Actions

Move Tasks with Drag and Drop

Task Actions 20 min read

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:

jsx
<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:

javascript
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:

javascript
function handleDragOver(event) {
  event.preventDefault();
}

Then read the task id on drop and update its status:

javascript
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:

jsx
<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.