react-beautiful-dnd is a robust and accessible drag and drop library for React applications. It is designed to be highly performant, customizable, and provide a polished user experience for lists, reordering, and moving items between different lists. Unlike some other drag and drop libraries, react-beautiful-dnd focuses on providing a natural and intuitive experience, emphasizing fluid animations, keyboard support, and screen reader compatibility.
Key components and concepts:
1. `DragDropContext`: This is the top-level component that wraps your entire drag and drop interface. It manages the state and lifecycle of the drag and drop operations within its scope. It requires an `onDragEnd` prop, which is a callback function that fires when a drag operation finishes (either by dropping an item or cancelling the drag). This function is crucial for updating your application's state (e.g., reordering a list based on the drag result).
2. `Droppable`: This component defines an area where `Draggable` items can be dropped. A `Droppable` needs a unique `droppableId` string. Its children must be a function (a render prop) that receives two arguments: `provided` and `snapshot`.
* `provided`: An object containing properties and methods for the `Droppable` area. Key properties include `provided.innerRef` (must be attached to the DOM element you're rendering) and `provided.placeholder` (an element that expands to create space for the dragging item, which you should render as a child).
* `snapshot`: An object containing information about the current drag state of the `Droppable` (e.g., `isDraggingOver`).
3. `Draggable`: This component makes an item within a `Droppable` area draggable. A `Draggable` needs a unique `draggableId` string and an `index` (its current position within the `Droppable` list). Similar to `Droppable`, its children must be a function (a render prop) that receives `provided` and `snapshot`.
* `provided`: Contains properties for the `Draggable` item, including `provided.draggableProps` (properties to apply to the root DOM node of your draggable), `provided.dragHandleProps` (properties to apply to the element that will be used to initiate the drag), and `provided.innerRef` (must be attached to the root DOM element you're rendering for the draggable).
* `snapshot`: Contains information about the current drag state of the `Draggable` (e.g., `isDragging`, `isDropAnimating`).
How it works:
When a `Draggable` item is picked up, `react-beautiful-dnd` manages its visual representation and updates the `snapshot` props of relevant `Droppable` and `Draggable` components. When the item is dropped, the `onDragEnd` callback of `DragDropContext` is invoked with a `result` object. This `result` object contains information about the source (where the drag started) and destination (where it ended), allowing you to update your underlying data model (e.g., an array of items) to reflect the new order. The library then gracefully animates the items to their new positions.
`react-beautiful-dnd` abstracts away much of the complexity of managing drag and drop interactions, offering a powerful, accessible, and enjoyable experience for both developers and users.
Example Code
import React, { useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
// a little function to help us with reordering the result
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
// Styles for the items and droppable area
const getItemStyle = (isDragging, draggableStyle) => ({
userSelect: 'none',
padding: 16,
margin: '0 0 8px 0',
background: isDragging ? '#263B4A' : '#456C86',
color: 'white',
borderRadius: '4px',
boxShadow: isDragging ? '0px 4px 8px rgba(0,0,0,0.2)' : 'none',
transition: 'background-color 0.2s ease, box-shadow 0.2s ease',
...draggableStyle,
});
const getListStyle = (isDraggingOver) => ({
background: isDraggingOver ? '#cfe8ff' : '#ebf5ff',
padding: 8,
width: 250,
borderRadius: '8px',
minHeight: '300px',
border: '1px solid #cceeff'
});
function App() {
const [items, setItems] = useState([
{ id: 'item-1', content: 'Item 1' },
{ id: 'item-2', content: 'Item 2' },
{ id: 'item-3', content: 'Item 3' },
{ id: 'item-4', content: 'Item 4' },
{ id: 'item-5', content: 'Item 5' },
]);
const onDragEnd = (result) => {
// dropped outside the list
if (!result.destination) {
return;
}
const newItems = reorder(
items,
result.source.index,
result.destination.index
);
setItems(newItems);
};
return (
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
<h1>My Draggable List</h1>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable-list">
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}
>
{item.content}
</div>
)}
</Draggable>
))}
{provided.placeholder} { /* Important for creating space */ }
</div>
)}
</Droppable>
</DragDropContext>
<p style={{ marginTop: '20px', fontSize: '0.9em', color: '#666' }}>
<em>Drag and drop items to reorder them.</em>
</p>
</div>
);
}
export default App;








react-beautiful-dnd