AK

Ankur Kedia

Ankur

BlogProjects

Curious case of Drag and Drop

Transitioning from react-beautiful-dnd to dnd-kit

30 Jan, 20244 min read
drag-and-drop

This article was originally published on the epilot blog.

Introduction

Drag and drop may appear as a simple user interaction where you pick an item up and place it elsewhere, similar to organizing items on a Trello board or any Kanban-style interface where cards or information can be effortlessly rearranged with a click and drag.

However, this whole process hides a lot of complexity behind it. Starting with moving data between different parts, and getting the correct drop position. This challenge escalates when you have a nested layer of elements that can move across multiple levels.

To implement this, we don’t have to reinvent the wheel here, we have several libraries at our disposal. The most popular ones are:

  • react-beautiful-dnd : stands out as the most commonly used, it provides a clean and high-level API with a lot of abstraction. It was developed by Atlassian.
  • react-dnd : is quite powerful but a bit complex and requires some getting used to.
  • dnd-kit : is one of the newest ones, it is modern, light-weight, and performant.

Problem

We, at epilot have relied on react-beautiful-dnd extensively and in different parts of our app. However, we hit some roadblocks in certain contexts while trying some complex scenarios where it was not accurately predicting the drop location of the element. Here is one example.

rb-dndEpilot Workflow Builder with react-beautiful-dnd

We devised several hacks for specific edge cases but they fell short of solving all of the issues. The code to move element data based on drop position was turning into Spaghetti code because of those edge cases. The discontinuation of maintenance and support of react-beautiful-dnd was also not helping its case to keep using it.

Solution

Finally, we decided to explore alternative libraries that could solve our problems with a more explicit, intuitive, and simpler API. After evaluating several options, we settled with dnd-kit as it provided an explicit and simple API. An added benefit was that it also provides hooks API which is missing in some of the older libraries.

Key advantages of dnd-kit include:

  • Zero dependencies
  • Optimized Performance
  • Accessibility
  • Support for Multiple Input Methods
  • Comprehensive documentation and examples

Show me some code

Here are the codes for a simple drag-and-drop with both libraries.

// react-beautiful-dnd
export const DragDrop = ({ initialData }) => {
const [items, setItems] = useState(initialData);
const onDragEnd = () => { /** moving data **/ };
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<ul {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<DraggableItem item={item} key={item.id} index={index} />
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
);
};
const DraggableItem = ({ item, index }) => (
<Draggable draggableId={item.id} index={index}>
{(provided) => (
<li
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
{item.content}
</li>
)}
</Draggable>
);
// dnd-kit
export const DndKit = ({ initialData }) => {
const [items, setItems] = useState(initialData);
const onDragEnd = () => { /** moving data **/ };
const sensors = useSensors(useSensor(PointerSensor));
return (
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
<ul>
{items.map((item) => (
<DraggableItem item={item} key={item.id} />
))}
</ul>
</SortableContext>
</DndContext>
);
};
const DraggableItem = ({ item }) => {
const {
attributes,
isDragging,
listeners,
setNodeRef,
transform,
transition,
} = useSortable({
id: item.id,
});
const style = {
transform: CSS.Transform.toString(transform),
transition,
cursor: isDragging ? "grabbing" : "grab",
};
return (
<li
{...attributes}
{...listeners}
key={item.id}
data-dnd-id={item.id}
data-dnd-type="item"
ref={setNodeRef}
style={style}
>
{item.content}
</li>
);
};

Check out this Codesandbox for the complete code.

Among these code samples having the same functionality, you can tell that dnd-kit has a higher complexity but is also more comprehensive. It uses Sortable to address this as it is one of the use cases it solves. It aligns with our objective to solve more intricate scenarios with nested drag and drop and the ability to drag across different levels.

Key advantages with dnd-kit that came in handy include:

  • Custom Placeholder - It is one of the most desired use cases. Achieving this in react-beautiful-dnd can be challenging as it will have limited capabilities and a lot of JavaScript to attain a satisfactory state. In our scenario, we wanted to show a condensed version of the element with children during dragging, so we used DragOverlay with the React portal.
  • Collision Detection Strategies - It offers various strategies specific to different use cases providing control over element switching within the tree. You can even develop your custom strategy to fit your requirements.
  • Sorting Strategies - Similarly, it offers different sorting strategies enabling sorting of vertical lists, horizontal lists, or grids.

Check out this simplified version of our use case at Epilot featuring drag and drop functionality with nested elements in this Codesandbox.

Conclusion

Ultimately, the choice between the two depends on your specific requirements, preferences, and the level of customization you want. If you prefer a simpler and more opinionated approach, react-beautiful-dnd would be a better choice. If you are looking for more customization and control, dnd-kit might be fit your needs better.

#drag-and-drop#react#javascript
Discuss on Twitter

Share on