Drag and Drop Sortable List Using ReactJS
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: 'https://media.w3wiki.net/wp-content/uploads/20230816223829/BeginnergforBeginner-logo-1.png' , }, { id: 2, name: 'John Doe' , image: 'https://media.w3wiki.net/wp-content/uploads/20230721212159/gfg-logo.jpeg' , }, { id: 3, name: 'Jane Smith' , image: 'https://media.w3wiki.net/wp-content/uploads/20230909123918/w3wiki-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 ( 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap' ); * { 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:
Contact Us