IMPLEMENTING BEAUTIFUL DRAG & DROP : REACT BEAUTIFUL DND STEP BY STEP
Building Web Apps is no more a big deal , its as boring as car with no wheel.
But let me help you make it fancy with REACT-BEAUTIFUL-DND
Now Drag-Drop your components and make a car with flying wings and of course with wheels.
Please ignore the 👆 poem 😋😂🤣
Contents
- React Drag and Drop
- React-Beautiful-DND (introduction and installation)
- Create Normal Components
- Convert created components to DND components
- Result
- Github Link
Quick Links to other ReactJS Tutorials
1. REACT DRAG AND DROP
There are many React libraries that helps you make Drag and Drop react components.
Follow this link for list of 32 widely used React DND packages : link
In this blog we will be using react library called react-beautiful-dnd for creating DND components. React-Beautiful-DND is one of the most user friendly and easy to use Drag and Drop (DND) react library, developed by the creators of JIRA, Alex Reardon.
2. React-Beautiful-DND
2.1 Brief Introduction
We will be referring to React-Beautiful-DND as rbd
In rbd library the DND components are created using 3 main components:
<DragDropContext/>
=> defines the area for entire drag n drop operation<Droppable/>
=> defines the area where Draggable items can be dropped<Draggable/>
=> defines the actual item that can be dragged around and dropped in Droppable area
Each DragDropContext can have multiple Droppables and each Droppables can have multiple Draggables defined inside them.
2.2 BRD Library Installation
First create a react app using command npx create-react-app my_app
.
Read this detailed tutorial on how to create first react app : link
After the app is created you can install the RBD library using the command npm i --save react-beautiful-dnd
for more details please visit the link https://www.npmjs.com/package/react-beautiful-dnd
CreateAPP is a git branch name. You can find the full code at Github link
3. Creating normal React components
After creating new React App run the server using the command npm start.
The react app will be rendered in browser locally at default port 3000 as shown in the image.
3.1 Change the existing code
change the code in file appname/src/App.js to
// Filename : App.jsx
import './App.css';function App() {
return (
<div className="App">
<header className="App-header">
<h4>Hands on React-Beautiful-DND</h4>
</header>
</div>
);
}
export default App;
3.2 Add new Components
Now we will create some normal components which we will later convert to DND components. In the file ListComponent.jsx we will create some list items and render it by importing that file in App.js
// Filename : ListComponent.jsximport React from 'react';export function ListComponents({Marvel, DC}) {
return (
<div style={{ width: '100%', display: 'flex' }}>
<div style={{ width: '25%', margin: 'auto' }}>
<ul style={{ listStyleType: 'none', textAlign: 'left' }} >
<h6>Marvel SuperHeroes</h6>
{Marvel.map((data, index) => (
<li key={index}>
{data}
</li>
))}
</ul>
</div>
<div style={{ width: '25%', margin: 'auto' }}>
<ul style={{ listStyleType: 'none', textAlign: 'left' }}>
<h6>DC SuperHeroes</h6>
{DC.map((data, index) => (
<li key={index}>
{data}
</li>
))}
</ul>
</div>
</div>
)}
Marvel and DC are normal constant list variables. To render these lists in ReactJS we can use map() function. map() function will iterate over each element/item in list and renders each data element the way we want. we need to pass unique key to each rendered elements for efficient re-rendering of DOM elements.
To import and render ListComponent.jsx in App.js change the code in App.js to
// FileName: App.js
import './App.css';// importing components from another files
import { ListComponents } from "./ListComponent";function App() {// List 1 consisting of all MARVEL super heroes
const list1 = ['Captain America', 'Iron Man', 'SpiderMan', 'Thor', 'Hulk', 'Black Widow', 'Loki', 'Black Panther', 'Deadpool', 'Doctor Strange', 'Ant Man', 'Captain Marvel']// List 2 consisting of all DC super heroes
const list2 = ['BatMan', 'SuperMan', 'Wonder Woman', 'Flash', 'Green Lantern', 'AquaMan', 'Robin', 'Cyborg', 'StarFire', 'HawkGirl', 'Shazam', '']return (
<div className="App">
<header className="App-header">
<h4>Hands on React-Beautiful-DND</h4>
<ListComponents Marvel={list1} DC={list2} />
</header>
</div>
);
}
export default App;
After the ListComponent.jsx is imported in App.js the output will look like this.
4. Convert created components to DND components
Now we have successfully created a two list components now next step is to covert them to DND components to allow Drag&Drop operations.
Time to create Drag and Drop Components 😍😍
4.1 Create DragDropContext
we will import DragDropContext from library react-beautiful-dnd in App.js and wrap the whole App inside this context. This will wrap other two components, Droppable and Draggable BRD components. There are props such as onDragStart, onDragUpdate and onDragEnd defined but onDragEnd is more than enough to perform reordering, adding and removing items.
Modified App.js code after adding DragDropContext
// FileName: App.jsimport './App.css';
import React from 'react';// importing components from another files
import { ListComponents } from "./ListComponent";// imports related to DND
import { DragDropContext } from 'react-beautiful-dnd';function App() { // List 1 consisting of all MARVEL super heroes
const [list1, setList1] = React.useState(['Captain America', 'Iron Man', 'SpiderMan', 'Thor', 'Hulk', 'Black Widow', 'Loki', 'Black Panther', 'Deadpool', 'Doctor Strange', 'Ant Man', 'Captain Marvel']) // List 2 consisting of all DC super heroes
const [list2, setList2] = React.useState(['BatMan', 'SuperMan', 'Wonder Woman', 'Flash', 'Green Lantern', 'AquaMan', 'Robin', 'Cyborg', 'StarFire', 'HawkGirl', 'Shazam']) // Function for deleting items from list using index
const deleteItem = (list, index) => {
return list.splice(index, 1)
} // Function called when Drag Ends
const onDragEnd = (result) => {
// getting the source and destination object
const { source, destination } = result
if (!destination)
return;
if (source.droppableId === destination.droppableId) {
if (source.droppableId === "Marvel_drop_area") {
let tempList = list1
const removed = deleteItem(tempList, source.index)
tempList.splice(destination.index, 0, removed)
setList1(tempList)
}
else {
let tempList = list2
const removed = deleteItem(tempList, source.index)
tempList.splice(destination.index, 0, removed)
setList2(tempList)
}
} else {
let tempList1 = list1
let tempList2 = list2
if (source.droppableId === "Marvel_drop_area") {
const removed = deleteItem(tempList1, source.index)
tempList2.splice(destination.index, 0, removed)
setList1(tempList1)
setList2(tempList2)
} else {
const removed = deleteItem(tempList2, source.index)
tempList1.splice(destination.index, 0, removed)
setList1(tempList1)
setList2(tempList2)
}
}
}return (
<DragDropContext onDragEnd={onDragEnd}>
<div className="App">
<header className="App-header">
<h4>Hands on React-Beautiful-DND</h4>
<ListComponents Marvel={list1} DC={list2} />
</header>
</div>
</DragDropContext>
)
}
export default App;
4.2 Create Droppable and Draggable Components
we will import Droppable and Draggable from library react-beautiful-dnd in ListComponent.jsx. Draggagle must be nested inside Droppable and Droppable should be nested inside DragDropContext.
Droppable defines the droppable area where items can be dragged and dropped. Each droppable component will have a unique droppableId prop. Droppable component provides variables such as :
provided.innerRef:
a react reference variable to manipulate the DOM elementsprovided.droppableProps:
provides the default CSS styling for drag and drop functionalityprovided.placeholder:
provides an extra space in Droppable area for the item that is currently being dragged.snapshot:
snapshot.isDraggingOver
can be used to get the drag&drop state to apply conditional CSS styling.
Draggable defines the actual item that needs to be dragged. It must be nested inside Droppable component. We must provide values for
draggableId
for uniquely identifying the dragged items.index:
for identifying the data in the list that is currently being dragged in source and in destination identifying the data in the list below which the dragged item must be placed.
Modified ListComponent.jsx after adding Droppable and Draggable
// Filename : ListComponent.jsximport React from 'react';// imports related to DND
import { Droppable, Draggable } from 'react-beautiful-dnd';export function ListComponents({ Marvel, DC }) {
const getListStyle = isDraggingOver => ({
background: isDraggingOver ? "lightblue" : "darkgrey",
width: '21%',
margin: 'auto',
});
const getItemStyle = (isDragging, draggableStyle) => ({
userSelect: "none",
background: isDragging ? "darkgrey" : "white",
color: isDragging ? "white" : "black",
padding: isDragging ? '0%' : '2%',
paddingLeft: '2%',
margin: '0%',
fontSize: '17px',
borderBottom: '0.5px solid gray',
// styles we need to apply on draggables
...draggableStyle
}); return (
<div style={{ width: '100%', display: 'flex' }}>
<Droppable droppableId="Marvel_drop_area" >
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
>
<ul style={{ listStyleType: 'none', textAlign: 'left', padding: '0%', width: '100%' }} >
<h6 style={{ paddingLeft: '2%' }}>Marvel SuperHeroes</h6> {Marvel.map((data, index) => (
<Draggable key={data}
draggableId={`${data}${index}`} index={index}>
{(provided, snapshot) => (
<li
key={index}
ref={provided.innerRef}
...provided.draggableProps}
...provided.dragHandleProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}
>
{data}
</li>
)}
</Draggable>
))}
</ul>
{provided.placeholder}
</div>
)}
</Droppable>
<Droppable droppableId="DC_drop_area" >
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
>
<ul style={{ listStyleType: 'none', textAlign: 'left', padding: '0%', width: '100%' }} >
<h6 style={{ paddingLeft: '2%' }}>DC SuperHeroes</h6>
{DC.map((data, index) => (
<Draggable key={data} draggableId={`${data}${index}`} index={index}>
{(provided, snapshot) => (
<li
key={index}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}
>
{data}
</li>
)}
</Draggable>
))}
</ul>
{provided.placeholder}
</div>
)}
</Droppable>
</div>
)
}
5. RESULT
6. Github Link
You can find the full code in github using the link : https://github.com/ashikrai/DND-React-Beautiful-DND.git
Read more of my articles on React App Development and other awesome React packages
Part 1: How to create a new React App | by KIHSA Rai | Medium | Medium
Part 2: Easy Way To Create ReactJS Components | by KIHSA Rai | Jul, 2021 | Medium
Learning ReactJS: Two-Way Data Binding | by KIHSA Rai | May, 2022 | Medium