How I create a simple drag drop for website builder
Tags: react, beginners, tutorial
Published: 2024-02-23 06:19:22

## React drag and drop 

Welcome to my first blog post! 

Today, I want to share my experience with implementing drag and drop functionality in a React applicatio. Recently, I was working on a page builder project where I needed to allow users to drag and drop elements to customize their pages. In this post, I'll walk you through a basic example of how I achieved this in React.

> You can interact with the example above to see how the drag and > drop functionality works. Let's break down the key parts of this > implementation.

{% codepen https://codepen.io/addimohammedsaid/pen/zYbVYLb 
 %}

> **Note:**
> I would recommend to have a look at the [drag and drop HTML API](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent).

### Creating Draggable Items

To make an element draggable, we need to simply add the `draggable `attribute. This attribute allows the element to be dragged.

### Handling Drag Over and Drop

We also need to handle the onDragOver and onDrop events on the droppable area. The handleDragOver event handler is used to prevent the default behavior of the browser, allowing the element to be dropped. In the handleDrop event handler, we get the data that was set in the handleDragStart event and add it to our list of items.

The `setData` function accepts the first argument as a key that we can later use to retrieve the data from another element. In this example, we've chosen two different keys `component `and `swap`, but it can be anything of type string you prefer.

```
import React from 'react';

const DraggableItem = ({ id, type, element }) => {
  const handleDragStart = (event) => {
    event.dataTransfer.setData('component', JSON.stringify({ id, type, element }));
  };

  return (
    <div
      draggable
      onDragStart={handleDragStart}
      className="p-2 m-1 border border-gray-300 cursor-move"
    >
      {element}
    </div>
  );
};

export default DraggableItem;

```

### Creating the Sidebar
In the Sidebar component, we render a list of DraggableItem components which could be the placeholder of your text, image, container..etc. Each DraggableItem represents an item in the sidebar that can be dragged. We pass the id, type, and element props to each DraggableItem.

```
import React from 'react';
import DraggableItem from './DraggableItem';

const Sidebar = () => {
  const elements = [
    { id: '1', type: 'text', element: 'Text Element' },
    { id: '2', type: 'image', element: 'Image Element' },
    { id: '3', type: 'button', element: 'Button Element' },
  ];

  return (
    <div className="w-48 p-4 border-r border-gray-300">
      {elements.map((el) => (
        <DraggableItem key={el.id} {...el} />
      ))}
    </div>
  );
};

export default Sidebar;

```

### Creating the Droppable List
The DroppableList component represents a droppable area where the items can be dropped and rearranged. We use the useState hook to manage the list of dropped items (items). We also listen to the onDragOver event and onDrop event to handle the drop event. 

In the handleDrop event handler, we prevent the default behavior to allow dropping and then update the items state with the dropped data. Additionally, we implement the moveItem function to rearrange the items when they are dropped in a new position.

```
import React, { useState } from 'react';

// Droppable list component where items can be dropped and rearranged
const DroppableList = () => {
   // State to store the items in the droppable list
  const [items, setItems] = useState([]);

  const handleDragOver = (event) => {
    // Prevent default when dragging over
    event.preventDefault();
  };

  const handleDrop = (event) => {
    event.preventDefault();
    // Get the data of the dropped item
    const data = JSON.parse(event.dataTransfer.getData('component'));
     // Check if data exists
    if (!data) return;
     // Add the dropped item to the list
    setItems([...items, data]);
  };
  
  // Function to move an item in the list
  const moveItem = (dragIndex, hoverIndex) => {
    const draggedItem = items[dragIndex];
    const hoveItem = items[hoverIndex];
    const updatedItems = [...items];
    updatedItems.splice(dragIndex, 1, hoveItem);
    updatedItems.splice(hoverIndex, 1, draggedItem);
    setItems(updatedItems);
  };

  const handleSwap = (event, hoverIndex) => {
    event.preventDefault();
    const dragIndex = Number(event.dataTransfer.getData('swap'));
    if(dragIndex < 0 || dragIndex === hoverIndex) return;
     // Rearrange the items in the list
    moveItem(dragIndex, hoverIndex);
  };

  return (
    <div
      className="flex-1 p-4 min-h-32 border border-gray-300"
      onDragOver={handleDragOver}
      onDrop={handleDrop}
    >
      {items.map((item, index) => (
        <div
          key={item.id+index}
          draggable
          onDragStart={(event) => event.dataTransfer.setData('swap', index)}
          onDrop={(event) => handleSwap(event, index)}
          className="p-2 m-1 border border-gray-300 cursor-move"
        >
          {item.element}
        </div>
      ))}
    </div>
  );
};

export default DroppableList;

```

Putting It All Together
Finally, let's create an App component that combines the Sidebar and DroppableList components:

```
import React from 'react';
import Sidebar from './Sidebar';
import DroppableList from './DroppableList';

const App = () => {
  return (
    <div style={{ display: 'flex' }}>
      <Sidebar />
      <DroppableList />
    </div>
  );
};

export default App;
```

Conclusion
In this tutorial, we learned how to implement a simple drag-and-drop functionality in a React application.

- Use the draggable attribute to make an element draggable.
- Use the onDragStart, onDragOver, onDrop, and onDragEnd events to implement drag-and-drop functionality.
- When using the onDragStart event, set the data to be transferred using event.dataTransfer.setData.
- When using the onDrop event, prevent the default behavior to allow dropping.
- Use the useState hook to manage the state of the dropped items.

Feel free to customize this further and explore more :).