Sortable Drag and Drop with React and Tailwind CSS

In this tutorial, we’ll learn how to create a sortable drag-and-drop feature in a React application using Vite for quick and efficient development, along with Tailwind CSS for styling. This feature allows users to reorder items in a list by dragging and dropping them, enhancing the user experience of your web application.

Output Preview: Let us have a look at how the final output will look like.

Preview of Sortable Drag and Drop with React and Tailwind CSS

Prerequisites

Approach to Create a Sortable Drag and Drop

We’ll use Vite for setting up our React project quickly and efficiently. The main functionalities of our sortable drag-and-drop project include:

  • Creating a list of items that users can reorder by dragging and dropping.
  • Implementing drag-and-drop functionality using the react-dnd library.
  • Styling the interface with Tailwind CSS for a simple and modern look.

Steps to Create & Configure the Project

Step 1: Set up and Navigate to the project using the command

npx create-vite@latest sortable-drag-drop --template react
cd  sortable-drag-drop
npm install

Step 2: Install Required Libraries:

npm install react-dnd
npm install react-dnd-html5-backend

Step 3: Install Tailwind and Create the tailwind config file using the command

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Step 4: Rewrite the tailwind.config.js file as follows

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Step 5: Replace the index.css file by follows:

@tailwind base;
@tailwind components;
@tailwind utilities;

Step 6: Create components folder and create SortableList.jsx files

Project Structure:

Folder structure

The updated dependencies in package.json file will look like:

"dependencies": {
    "react": "^18.2.0",
    "react-dnd": "^16.0.1",
    "react-dnd-html5-backend": "^16.0.1",
    "react-dom": "^18.2.0"
},
"devDependencies": {
    "@types/react": "^18.2.56",
    "@types/react-dom": "^18.2.19",
    "@vitejs/plugin-react": "^4.2.1",
    "autoprefixer": "^10.4.18",
    "eslint": "^8.56.0",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.5",
    "postcss": "^8.4.35",
    "tailwindcss": "^3.4.1",
    "vite": "^5.1.4"
}

Example Code:

Javascript
// SortableList.jsx

import React, { useState } from 'react';
import { useDrag, useDrop } from 'react-dnd';

const ItemTypes = {
    CARD: 'card',
};

const SortableList = ({ items }) => {
    const [sortedItems, setSortedItems] = useState(items);

    const moveItem = (dragIndex, hoverIndex) => {
        const draggedItem = sortedItems[dragIndex];
        const newSortedItems = [...sortedItems];
        newSortedItems.splice(dragIndex, 1);
        newSortedItems.splice(hoverIndex, 0, draggedItem);
        setSortedItems(newSortedItems);
    };

    const Item = ({ item, index }) => {
        const [{ isDragging }, drag] = useDrag({
            type: ItemTypes.CARD,
            item: { type: ItemTypes.CARD, index },
            collect: (monitor) => ({
                isDragging: monitor.isDragging(),
            }),
        });

        const [, drop] = useDrop({
            accept: ItemTypes.CARD,
            hover: (item) => {
                const dragIndex = item.index;
                const hoverIndex = index;

                if (dragIndex === hoverIndex) {
                    return;
                }

                moveItem(dragIndex, hoverIndex);
                item.index = hoverIndex;
            },
        });

        const opacity = isDragging ? 0.5 : 1;

        return (
            <li
                ref={(node) => drag(drop(node))}
                className={
`bg-gray-100 p-4 my-2 rounded-md shadow-md ${isDragging ? 'opacity-50' : ''}`
                }
                style={{ cursor: 'move' }}
            >
                {item}
            </li>
        );
    };

    return (
        <ul>
            {sortedItems.map((item, index) => (
                <Item key={item} item={item} index={index} />
            ))}
        </ul>
    );
};

export default SortableList;
Javascript
// App.js

import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import './App.css';
import SortableList from './components/SortableList';

function App() {
  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

  return (
    <DndProvider backend={HTML5Backend}>
      <>
        <h1 className='text-3xl font-bold text-green-600 mb-8'>
            Beginner For Beginner: Sortable Drag and Drop
        </h1>

        <SortableList items={items} />
      </>
    </DndProvider>
  );
}

export default App;

To Run the Application, type the following command in terminal:

npm run dev

Output: Now, open your browser and navigate to http://localhost:5173 to see the sortable drag-and-drop application in action

Sortable Drag and Drop with React and Tailwind CSS