Super Simple Drag N' Drop from Scratch in React (without dependencies)
Tags: react, dragndrop, programming, tutorial
Published: 2021-11-02 11:17:30

**Read the updated version of this tutorial [here](https://dev.to/wolfmath/drag-and-drop-with-react-519m)**

I recently had been tasked to create Drag N' Drop component from scratch - so no `npm i react-beautiful-dnd`. Before tackling this I decided (with a helpful suggestion from a coworker) to write it in CodeSandbox first. Now I get to share it with you! 

**Disclaimer**: This is how _I_ approached the problem, but I have no doubts that there are other/better ways to go about doing it. If you feel there's a better way I'd appreciate you writing it in the comments. This is **very** rudimentary, so if you decide to use it know that you'd need to make refinements.

#Set Up

First I created 3 groups to drag and drop between, then I iterated over them to create the `div`s that they would create. Then I created an array of 7 objects that can be dragged from one group to another. These are saved in state, hence the `useState` import.

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

export default function Dnd() {
  const groups = ["group1", "group2", "group3"];
  const [items, setitems] = useState([
    { id: 1, group: groups[0], value: "Chicken" },
    { id: 2, group: groups[0], value: "Monkey" },
    { id: 3, group: groups[0], value: "Duck" },
    { id: 4, group: groups[1], value: "Rhino" },
    { id: 5, group: groups[1], value: "Sandwich" },
    { id: 6, group: groups[2], value: "Ostrich" },
    { id: 7, group: groups[2], value: "Flamingo" }
  ]);

  return (
    <div className="groups">
      {groups.map((group) => (
        <div
          className="group"
          key={group}
        >
          <h1 className="title">{group}</h1>
          <div>
            {items
              .filter((item) => item.group === group)
              .map((thing) => (
                <div
                  key={thing.id}
                  id={thing.id}
                  className="thing"
                >
                  {thing.value}
                </div>
              ))}
          </div>
        </div>
      ))}
    </div>
  );
}
```
Then we have the `scss` that goes along with it (it's not pretty, but just enough to get the visuals right).

```
.groups {
  display: flex;
  margin: 20px;
  padding: 20px;
  flex-wrap: wrap;

  .group {
    margin: 20px;
    padding: 20px;
    min-height: 16rem;
    background-color: green;

    .title{
      color: white;
      padding: 0;
      margin-top: 0;
    }
  }
  
  .group-hover {
    margin: 20px;
    padding: 20px;
    background-color: darkgreen
  }
}

.thing {
  background-color: yellow;
  color: blue;
  margin: 5px;
  padding: 5px;
  border: 2px green;
}
```

Together these two things create 7 yellow boxes inside 3 green boxes.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nqhqvwnih0z1d65jrq9w.png)

#DND
Now we get to discuss how to start the DND functionality.

First is to set the _thing_ (animal) `div` to be `draggable`. This will allow the click and drag of the `div`, but it won't actually do anything.

 ```
<div
  key={thing.id}
  id={thing.id}
  className="thing"
  draggable
>
```

Next we need to have a little understanding of the [HTML5 onDrag events](https://www.w3schools.com/jsref/event_ondrag.asp). There are different events for the dragged item and the item being dragged over/onto.

I set up some state to know which item is being dragged at any given time then on the dragged item I set the state `onDragStart` and I created a function to handle the dragStart.



```
...

const [dragging, setDragging] = useState();

...  

const handleDragStart = (e) => {
  setDragging(e.target);
};

...

<div
  ...
  draggable
  onDragStart={(e) => handleDragStart(e)}
>
```

Lastly we need to handle what happens to the dragged over group. So I just have the animal added to the group as soon as it's dragged into the new group, but you can edit that behavior later. I'm using the `onDragEnter` which fires **once** when the dragged item enters the div.

```
<div
  className="group"
  key={group}
  onDragEnter={(e) => handleDragEnter(e, group)}
>
```

Then I created the `handleDragEnter` function to set the state of the dragged item to the group of that it's being dragged into.

```
const handleDragEnter = (e, group) => {
  setitems([...items, (items[dragging.id - 1].group = group)]);
};
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30iec6r9raaes3q1l1nx.gif)

Now the whole DND should be fully functional! Here's all the code put together and the [CodeSandbox code](https://bit.ly/3jYsBFG)!

```
import React, { useState } from "react";
import "./Dnd.scss";

export default function Dnd() {
  const groups = ["group1", "group2", "group3"];
  const [items, setitems] = useState([
    { id: 1, group: groups[0], value: "Chicken" },
    { id: 2, group: groups[0], value: "Monkey" },
    { id: 3, group: groups[0], value: "Duck" },
    { id: 4, group: groups[1], value: "Rhino" },
    { id: 5, group: groups[1], value: "Sandwich" },
    { id: 6, group: groups[2], value: "Ostrich" },
    { id: 7, group: groups[2], value: "Flamingo" }
  ]);

  const [dragging, setDragging] = useState();

  const handleDragStart = (e) => {
    setDragging(e.target);
  };

  const onDragEnter = (e, group) => {
    setitems([...items, (items[dragging.id - 1].group = group)]);
  };

  return (
    <div className="groups">
      {groups.map((group) => (
        <div
          className="group"
          key={group}
          onDragEnter={(e) => onDragEnter(e, group)}
        >
          <h1 className="title">{group}</h1>
          <div>
            {items
              .filter((item) => item.group === group)
              .map((thing) => (
                <div
                  key={thing.id}
                  id={thing.id}
                  className="thing"
                  draggable
                  onDragStart={(e) => handleDragStart(e)}
                >
                  {thing.value}
                </div>
              ))}
          </div>
        </div>
      ))}
    </div>
  );
}
```