In this article, we’ll create a Drag and Drop sortable list using React JS. Within this web application, users can effortlessly rearrange a list of items through the simple act of dragging and dropping.
Preview Image:
Prerequisites
Approach:
- This React-based application, “Drag and Drop Sortable List,” allows users to reorder a list of items effortlessly. Users can drag and drop items within the list to change their order.
- The constructor serves to initialize various aspects of the component’s state. These include the list of items, the currently dragged item, and input fields for adding new items.
- The method handleDragStart is responsible for setting up the dragging item and enabling its draggable property. On the other hand, handleDragEnd clears the dragging item once it has been released.
- To allow item drops, handleDragOver comes into play. If a drop is valid, handleDrop takes care of rearranging the items accordingly. Additionally, both handleNameChange and handleImageChange update values in input fields.
Steps to Create the Application:
Step 1: Create a react application by using this command
npx create-react-app image-color-picker
Step 2: After creating your project folder, i.e. image-color-picker, use the following command to navigate to it:
cd image-color-picker
Step 3: Install required dependences
npm install react-icons --save
Project Structure:
package.json file will look like
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
"react-icons": "^4.11.0"
}
Example: Write the below code in App.js file and App.css in the src directory
Javascript
import React, { Component } from 'react' ;
import './App.css' ;
import { RiDragMove2Line } from 'react-icons/ri' ;
class App extends Component { constructor(props) {
super (props);
this .state = {
items: [
{
id: 1,
name: 'Kristina Zasiadko' ,
image:
},
{
id: 2,
name: 'John Doe' ,
image:
},
{
id: 3,
name: 'Jane Smith' ,
image:
'https://media.geeksforgeeks.org/wp-content/uploads/20230909123918/GeeksforGeeks-Wide-logo-black.png' ,
},
// Add more items here
],
draggingItem: null ,
newItemName: '' ,
newItemImage: '' ,
};
}
handleDragStart = (e, item) => {
this .setState({ draggingItem: item });
e.dataTransfer.setData( 'text/plain' , '' );
};
handleDragEnd = () => {
this .setState({ draggingItem: null });
};
handleDragOver = (e) => {
e.preventDefault();
};
handleDrop = (e, targetItem) => {
const { draggingItem, items } = this .state;
if (!draggingItem) return ;
const currentIndex = items.indexOf(draggingItem);
const targetIndex = items.indexOf(targetItem);
if (currentIndex !== -1 && targetIndex !== -1) {
items.splice(currentIndex, 1);
items.splice(targetIndex, 0, draggingItem);
this .setState({ items });
}
};
handleNameChange = (e) => {
this .setState({ newItemName: e.target.value });
};
handleImageChange = (e) => {
this .setState({ newItemImage: e.target.value });
};
addNewItem = () => {
// Generate a unique ID for the new item
const newItemId =
Math.max(... this .state.items.map((item)
=> item.id)) + 1;
const newItem = {
id: newItemId,
name: this .state.newItemName,
image: this .state.newItemImage,
};
// Add the new item to the state
this .setState({
items: [... this .state.items, newItem],
newItemName: '' , // Clear the input fields
newItemImage: '' ,
});
};
render() {
return (
<div className= "sortable-list" >
<div className= "new-item" >
<input
type= "text"
placeholder= "Name"
value={ this .state.newItemName}
onChange={ this .handleNameChange}
className= "input-field"
/>
<input
type= "text"
placeholder= "Image URL"
value={ this .state.newItemImage}
onChange={ this .handleImageChange}
className= "input-field"
/>
<button onClick={ this .addNewItem}
className= "add-button" >
Add New Item
</button>
</div>
{ this .state.items.map((item, index) => (
<div
key={item.id}
className=
{`item ${item === this .state.draggingItem ?
'dragging' : ''
}`}
draggable= "true"
onDragStart={(e) =>
this .handleDragStart(e, item)}
onDragEnd={ this .handleDragEnd}
onDragOver={ this .handleDragOver}
onDrop={(e) => this .handleDrop(e, item)}
>
<div className= "details" >
<img src={item.image} alt={item.name} />
<span>{item.name}</span>
</div>
{ /* Use the React icon component */ }
<RiDragMove2Line />
</div>
))}
</div>
);
}
} export default App;
|
CSS
@import url (
* { margin : 0 ;
padding : 0 ;
box-sizing: border-box;
font-family : 'Poppins' , sans-serif ;
} body { display : flex;
align-items: center ;
justify- content : center ;
min-height : 100 vh;
background : #f4f4f4 ;
} .sortable-list { width : 425px ;
background : #ffffff ;
border-radius: 10px ;
padding : 20px ;
box-shadow: 0 13px 46px rgba( 0 , 0 , 0 , 0.1 );
} .input-field { padding : 10px ;
margin : 8px 0 ;
border : 1px solid #ccc ;
border-radius: 14px ;
font-size : 16px ;
width : 100% ;
box-shadow: 0 3px 16px rgba( 0 , 0 , 0 , 0.1 );
} .add-button { background-color : #007bff ;
color : white ;
border : none ;
border-radius: 14px ;
padding : 10px 20px ;
cursor : pointer ;
font-size : 16px ;
width : 100% ;
transition: background-color 0.3 s ease;
box-shadow: 0 3px 16px rgba( 0 , 0 , 0 , 0.1 );
} .add-button:hover { background-color : #0056b3 ;
} .sortable-list .item { margin-top : 1 rem;
border : 1px solid #ccc ;
justify- content : space-between;
list-style : none ;
display : flex;
cursor : move ;
background : #ffffff ;
align-items: center ;
border-radius: 10px ;
padding : 15px ;
margin-bottom : 10px ;
box-shadow: 0 3px 6px rgba( 0 , 0 , 0 , 0.1 );
} .item .details { display : flex;
align-items: center ;
} .item .details img { height : 60px ;
width : 60px ;
pointer-events: none ;
margin-right : 15px ;
object-fit: cover;
border-radius: 50% ;
} .item .details span { font-size : 1.2 rem;
font-weight : 500 ;
color : #333 ;
} .item i { color : #474747 ;
font-size : 1.13 rem;
} .item.dragging { opacity: 0.6 ;
} .item.dragging .details, .item.dragging i { opacity: 0.8 ;
transform: scale( 1.02 );
background : #f0f0f0 ;
} |
Steps to run the Application:
- Step 1: Type the following command in the terminal:
npm start
- Step 2: Type the following URL in the browser:
http://localhost:3000/
Output: