This article was originally published on the epilot blog.
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:
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.
Epilot 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.
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:
Here are the codes for a simple drag-and-drop with both libraries.
// react-beautiful-dndexport 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-kitexport const DndKit = ({ initialData }) => {const [items, setItems] = useState(initialData);const onDragEnd = () => { /** moving data **/ };const sensors = useSensors(useSensor(PointerSensor));return (<DndContextsensors={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:
Check out this simplified version of our use case at Epilot featuring drag and drop functionality with nested elements in this Codesandbox.
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.