IMPLEMENTING BEAUTIFUL DRAG & DROP : REACT BEAUTIFUL DND STEP BY STEP

KIHSA Rai
Nerd For Tech
Published in
8 min readJul 24, 2021

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

  1. React Drag and Drop
  2. React-Beautiful-DND (introduction and installation)
  3. Create Normal Components
  4. Convert created components to DND components
  5. Result
  6. Github Link

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:

BRD main components
Three main Components or BRD. Image Source: link
  • <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

install react BRD library
Command to install react BRD library

CreateAPP is a git branch name. You can find the full code at Github link

3. Creating normal React components

Locally running react app
React app running locally at localhost:3000

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

Modified App.js
// 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 elements
  • provided.droppableProps: provides the default CSS styling for drag and drop functionality
  • provided.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

Drag and Drop using React-Beautiful-DND

6. Github Link

You can find the full code in github using the link : https://github.com/ashikrai/DND-React-Beautiful-DND.git

--

--

KIHSA Rai
Nerd For Tech

I'm a Software Engineer experienced in web tech (ReactJS, TypeScript, GraphQL), Payment, RPA, C++, Python, Android, AWS. I'm always learning and improving.