What is @hello-pangea/dnd?
@hello-pangea/dnd is a powerful and flexible drag-and-drop library for React. It allows developers to create complex drag-and-drop interfaces with ease, supporting features like reordering lists, moving items between lists, and more.
Reordering a List
This code demonstrates how to reorder items in a list using @hello-pangea/dnd. It sets up a drag-and-drop context, defines a reorder function, and handles the drag end event to update the state with the reordered items.
import React from 'react';
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const App = () => {
const [items, setItems] = React.useState(['Item 1', 'Item 2', 'Item 3']);
const onDragEnd = (result) => {
if (!result.destination) return;
const reorderedItems = reorder(items, result.source.index, result.destination.index);
setItems(reorderedItems);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<Draggable key={item} draggableId={item} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
};
export default App;
Moving Items Between Lists
This code demonstrates how to move items between two lists using @hello-pangea/dnd. It sets up a drag-and-drop context, defines a move function, and handles the drag end event to update the state with the moved items.
import React from 'react';
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
const move = (source, destination, droppableSource, droppableDestination) => {
const sourceClone = Array.from(source);
const destClone = Array.from(destination);
const [removed] = sourceClone.splice(droppableSource.index, 1);
destClone.splice(droppableDestination.index, 0, removed);
const result = {};
result[droppableSource.droppableId] = sourceClone;
result[droppableDestination.droppableId] = destClone;
return result;
};
const App = () => {
const [state, setState] = React.useState({
droppable1: ['Item 1', 'Item 2', 'Item 3'],
droppable2: ['Item 4', 'Item 5', 'Item 6']
});
const onDragEnd = (result) => {
const { source, destination } = result;
if (!destination) return;
if (source.droppableId === destination.droppableId) return;
const movedItems = move(
state[source.droppableId],
state[destination.droppableId],
source,
destination
);
setState({
...state,
...movedItems
});
};
return (
<DragDropContext onDragEnd={onDragEnd}>
{Object.keys(state).map((listId) => (
<Droppable key={listId} droppableId={listId}>
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{state[listId].map((item, index) => (
<Draggable key={item} draggableId={item} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
))}
</DragDropContext>
);
};
export default App;