How We Built a Custom Drag and Drop System in React (No Libraries)
Aug 20, 2025
Suraj Choudhury
Drag-and-drop UIs are everywhere—from Trello boards to reorderable lists. But most tutorials rely on third-party libraries that introduce complexity or limit customization. So, we built a custom drag-and-drop system in React from scratch, complete with mouse tracking, drop zones, and ghost cards. This post is not just a usage guide — it’s a deep dive into how each part works, why each handler exists, and how everything ties together.
Design Goals
Drag and drop using mouse events
No external dependencies
Drop indicators and ghost previews
Pure React — no refs passed around manually
Component Breakdown
We built two main components:
DNDProvider
– manages global drag state, listens for global mouse events.DraggableItem
– individual draggable item, interacts with the provider and handles visuals.
What Do Event Handlers Do?
In the context of drag-and-drop, event handlers are essential to:
Start the drag
Track the cursor
Show drop indicators
Place a ghost card under the mouse
Handle where the item was dropped
Reset drag state properly
Let’s walk through each handler and understand why it’s used.
DNDProvider
: The Drag State Engine
handleMouseMovement
Purpose: Constantly update cursor position
Why: So the ghost card can follow the mouse accurately
Where used: In
DraggableItem
, to position the ghost element
handleMouseUp
Purpose: End drag operation globally
Why: If the user drops outside a valid zone, this prevents stale drag state
handleMouseLeaveWindow
Purpose: Cancel drag if mouse leaves window
Why: Prevents stuck drag state if user drags outside the browser window
DraggableItem
: The Draggable Unit
This component is responsible for interacting with the user — handling what happens when the item is clicked, moved, hovered over, or dropped.
handleDragStart
Purpose: Initiate dragging
Why:Stores which item is being draggedCaptures cursor offset (to position the ghost card correctly)
handleMouseEnterDropZone
Purpose: Indicate where the item would land — before or after this item
Why:Visual feedback is key for usabilityHelps calculate the drop index correctly
handleMouseLeaveDropZone
Purpose: Remove visual drop indicators
Why: Keeps UI clean and avoids confusion when no longer hovering
handleMouseUp
(in DragItem)
Purpose: Finalize drop
Why:
Determines where to move the item (based on
hoveredDropZonePosition
)Communicates the result to the parent via
onDragEnd
Ghost Card: Floating Preview
Purpose: Show a visual copy of the dragged item under the cursor
Why: Improves UX by confirming what’s being dragged
How: Uses the global mouse coordinates + local offset to match the original item position
Calculating Drop Target Index
Purpose: Determine the final index where the dragged item should be inserted
Why this logic?
If you're dragging an item downward and dropping it before another, the actual insertion point is one position above the visible target to account for index shift during removal.
If you're dragging upward, no adjustment is needed when dropping before.
For after positioning, the logic is reversed — inserting below the hovered item when moving downward, or adjusting downward if dragging upward to avoid jumping over the current target.
This ensures the drag-and-drop reorder behavior feels intuitive no matter the direction.
Final Flow Summary
User clicks item →
handleDragStart
Mouse moves → ghost card follows via
handleMouseMovement
User hovers over another item →
handleMouseEnterDropZone
activatesUser releases mouse →
handleMouseUp
triggersonDragEnd
List is reordered, UI re-renders
Bonus: How You Can Extend This
✅ Keyboard accessibility
🔄 Horizontal drag (like columns)
🎨 Animated reorder transitions
🪄 Multi-select drag support
Why This Works Well
This approach:
Keeps global state minimal and predictable
Ensures visual accuracy with mouse tracking
Provides full control over styling and UX
Makes your app lighter by avoiding heavy libraries
🔗 Live Demo on CodeSandbox
You can try the full working version of this drag-and-drop system here:
Connect with Us
Let us transform your ideas into impactful solutions by combining AI, design, and technology
Work with us
98%
Client satisfaction in project outcomes
20+ Projects done
Including web design, app development, and Branding
10+ Clients
Across industries and regions





10+