How to Use the Drag and Drop API for Kanban Board Functionality: A Complete Implementation Guide
Implement a fully functional Kanban board by combining draggable="true" attributes with the native HTML Drag and Drop API event handlers (ondragstart, ondragover, ondrop), then persist the board state across sessions using localStorage.
The jisan-mia/dom-projects repository contains a production-ready Kanban demonstration that builds an interactive task board using only vanilla HTML, CSS, and JavaScript. This implementation leverages the browser's native Drag and Drop API to enable seamless card movement between columns while maintaining state persistence without external frameworks or libraries.
Setting Up Draggable Cards and Drop Zones
To initiate drag operations, each task card must be explicitly marked as draggable and wired to event handlers that record the element being moved.
Making Task Cards Draggable
In projects/kanban/index.html, each task is rendered as a list item with the draggable attribute and an ondragstart handler:
<li class="drag-item"
draggable="true"
ondragstart="drag(event)"
contenteditable="true"
onfocusout="updateItem(/*index*/, /*column*/)">
Sample task
</li>
The drag() function in projects/kanban/script.js captures the dragged element:
function drag(e) {
draggedItem = e.target; // <li class="drag-item">
isDragging = true;
}
Configuring Column Drop Zones
Each Kanban column uses an unordered list (<ul>) as the drop container. The markup attaches three critical event handlers to manage the drop lifecycle:
<ul class="dragndrop-item-list"
id="backlog-list"
ondrop="dropItem(event)"
ondragover="allowDrop(event)"
ondragenter="dragEnter(0)">
</ul>
ondragover: Fires continuously while dragging over the elementondragenter: Fires once when entering the drop zoneondrop: Fires when the user releases the draggable element
Handling Core Drag and Drop Events
The JavaScript implementation in projects/kanban/script.js coordinates the movement of cards between the four columns: Backlog, Progress, Complete, and On-Hold.
Allowing Drops and Providing Visual Feedback
By default, browsers prevent dropping onto elements. The allowDrop() function overrides this behavior:
function allowDrop(e) {
e.preventDefault(); // Needed otherwise drop is blocked
}
Visual feedback is triggered via the dragEnter() function, which highlights the target column by adding an over class:
function dragEnter(columnIndex) {
listColumns[columnIndex].classList.add("over");
currentColumn = columnIndex;
}
The corresponding styles in projects/kanban/style.css define the highlight appearance:
.dragndrop-item-list.over {
background-color: #f0f8ff; /* light highlight when a column accepts a drop */
}
Executing the Drop Operation
When a user releases a card, the dropItem() function moves the DOM element and synchronizes the underlying data:
function dropItem(e) {
e.preventDefault();
listColumns.forEach(col => col.classList.remove("over")); // clear highlights
const parent = listColumns[currentColumn];
parent.appendChild(draggedItem); // move the <li> in the DOM
isDragging = false;
rebuildArrays(); // sync arrays <→ DOM <→ localStorage
}
Persisting Board State with localStorage
The Kanban board maintains four parallel arrays (backlogListArray, progressListArray, completeListArray, onHoldListArray) that mirror the DOM state. This architecture enables reliable data persistence across browser sessions.
Rebuilding Arrays After Movement
After each drop operation, rebuildArrays() reconstructs the column arrays based on the current DOM order. This ensures the JavaScript data structures remain synchronized with the visual layout before saving.
Saving to localStorage
The updateSavedColumns() function persists the arrays to localStorage using JSON serialization:
function updateSavedColumns() {
listArray = [backlogListArray, progressListArray, completeListArray, onHoldListArray];
const listNames = ["backlog", "progress", "complete", "onHold"];
listNames.forEach((name, i) => {
localStorage.setItem(`${name}Items`, JSON.stringify(listArray[i]));
});
}
On page initialization, updateDOM() retrieves these values or seeds default arrays, ensuring the board state survives page refreshes.
Adding Interactive Features
Beyond basic drag and drop functionality, the implementation supports inline editing and dynamic card creation.
Inline Card Editing
Each <li> element utilizes the contenteditable attribute, allowing users to modify task text directly. The onfocusout handler triggers updateItem() to propagate changes back to the corresponding array index and immediately persist the update via updateSavedColumns().
Creating New Cards
The board includes a hidden input area toggled by an "Add item" button. When users save new content, addItemToColumn() appends the text to the appropriate column array and refreshes the interface:
function addItemToColumn(columnIndex) {
const itemText = addItems[columnIndex].textContent;
const selectedArray = listArray[columnIndex];
selectedArray.push(itemText);
addItems[columnIndex].textContent = "";
updateDOM();
}
Styling the Drag Experience
The CSS in projects/kanban/style.css enhances usability through cursor states and visual transitions:
.drag-item {
cursor: grab;
}
.drag-item:active {
cursor: grabbing;
}
The .over class applied during dragEnter provides immediate spatial feedback, helping users identify valid drop targets before releasing the mouse button.
Summary
- Native API Only: The implementation uses the standard HTML Drag and Drop API (
draggable,ondragstart,ondragover,ondrop) without external dependencies. - Four-Column Structure: The board manages Backlog, Progress, Complete, and On-Hold columns through parallel arrays and DOM synchronization.
- Event Flow:
drag()records the source element,allowDrop()enables the target zone,dragEnter()highlights the destination, anddropItem()executes the move while triggering persistence. - State Persistence:
localStorageintegration viaupdateSavedColumns()andrebuildArrays()ensures data survives browser refreshes. - File Locations: Core logic resides in
projects/kanban/script.js, markup inprojects/kanban/index.html, and styling inprojects/kanban/style.css.
Frequently Asked Questions
How do I prevent the browser from blocking drop operations?
You must call event.preventDefault() inside the ondragover handler. According to the HTML Drag and Drop API specification, dropping is disabled by default on most elements unless this method explicitly allows the operation, as implemented in the allowDrop() function within projects/kanban/script.js.
What is the purpose of the rebuildArrays() function in the Kanban implementation?
The rebuildArrays() function iterates through the DOM elements in each column after a drop event and reconstructs the four JavaScript arrays (backlogListArray, progressListArray, etc.) to match the current visual order. This synchronization step is essential before calling updateSavedColumns() to persist the correct state to localStorage.
Can I implement this Kanban board without using localStorage?
Yes. While the jisan-mia/dom-projects implementation uses localStorage for persistence, you can remove the updateSavedColumns() calls and maintain state purely in memory using the four column arrays. Alternatively, you could replace the localStorage logic with API calls to a backend server by modifying the persistence layer in projects/kanban/script.js while retaining the same drag-and-drop event handlers.
How does the visual feedback work when dragging cards between columns?
The dragEnter() function applies an over CSS class to the target column's <ul> element when a draggable card enters its boundaries. The stylesheet in projects/kanban/style.css defines .dragndrop-item-list.over with a distinct background color (#f0f8ff), creating immediate visual confirmation of valid drop zones. The dropItem() function removes this class from all columns after the drop completes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →