ReviseAlgo Logo

JavaScript Projects

Build a Kanban Board (Drag & Drop)

Build a production-grade Kanban Board in JavaScript using native HTML5 Drag and Drop API, state persistence, and dynamic column mutations.

Last Updated: July 29, 2026 12 min read

1. Introduction

A Kanban Board organizes tasks into columns representing workflow states (e.g. Todo, In Progress, Done). Building a Kanban Board tests your understanding of the native HTML5 Drag and Drop API, event delegation, state serialization, and local storage persistence.

2. Why It Matters

Interactive drag-and-drop interfaces rely on event sequences: dragstart, dragover, dragenter, dragleave, drop, and dragend. Mastering these events without external third-party libraries gives you fine-grained control over UI responsiveness.

3. Real-World Analogy

Think of a Magnetic Whiteboard:

  • DragStart (Picking up a magnet): You pick up a task magnet from the "Todo" column. The magnet is held in your hand (active drag state).
  • DragOver (Hovering over column): You hover your hand over the "In Progress" column. The column highlights to show it can receive the magnet.
  • Drop (Sticking magnet to board): You release your hand over the target area. The magnet sticks to the new column, and the board registry updates its position.

4. State Model Architecture

5. HTML5 Drag and Drop Event Implementation

6. Practical Complete Interface

7. Common Mistakes

  • Forgetting to call e.preventDefault() inside dragover: By default, the browser prevents dropping elements onto web page elements. If you omit e.preventDefault() inside the dragover listener, the drop event will never fire.

8. Quick Quiz

Q1: Which event listener MUST invoke e.preventDefault() to allow an element to accept drop events?

A) dragstart

B) dragover

Answer: B — You must call e.preventDefault() inside the dragover event handler to enable drop target behavior.

9. Scenario-Based Challenge

The In-Column Card Reordering Challenge:

Currently, dropping a card appends it to the end of the column. Calculate mouse Y offsets relative to existing card siblings during dragover to determine the exact insertion index, enabling reordering within the same column.

10. Debugging Exercise

Explain why this drop event handler throws a DataTransfer security error, and how to fix it:

card.addEventListener('dragstart', (e) => {
  e.dataTransfer.setData('text/plain', card.id);
});

column.addEventListener('dragover', (e) => { // Bug: Attempting to read dataTransfer data during dragover! const id = e.dataTransfer.getData('text/plain'); console.log('Hovering card:', id); // Returns empty string or fails! Why? });

View Solution

Diagnosis: For security reasons, the HTML5 Drag and Drop specification restricts e.dataTransfer.getData() so that it can ONLY be read inside the drop event handler. Calling it inside dragover or dragenter returns an empty string.

Fix: Store the active dragged task ID in a local closure variable during dragstart, or read getData() exclusively inside the drop listener:

column.addEventListener('drop', (e) => {
  e.preventDefault();
  const id = e.dataTransfer.getData('text/plain'); // Allowed here!
});

11. Interview Questions

🟢 Q1: Explain the sequence of events in the HTML5 Drag and Drop API.

Answer:
1. dragstart: Fires on the source element when dragging begins.
2. drag: Fires continuously on the source element while dragging.
3. dragenter: Fires on a target container when the dragged element enters its boundaries.
4. dragover: Fires continuously on a target container while dragging over it. Must call e.preventDefault() to allow dropping.
5. dragleave: Fires when the dragged element leaves a target container.
6. drop: Fires on the target container when the mouse button is released over a valid target.
7. dragend: Fires on the source element after the drag operation completes (whether successful or canceled).

12. Production Considerations

  • Mobile Touch Support: The native HTML5 Drag and Drop API is not supported on mobile touchscreens. In production, provide touch event listeners (touchstart, touchmove, touchend) or use a touch-friendly polyfill.