🚀 A powerful drag and drop implementation in just 16 lines of JavaScript
Tags: javascript, html, css, webdev
Published: 2021-11-25 07:06:21

---
title: 🚀 A powerful drag and drop implementation in just 16 lines of JavaScript
published: true
date: 2021-11-25 06:44:02 UTC
tags: javascript, html, css, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txwj8wdjnowig11vbyf8.png
canonical_url: https://blog.siddu.tech/16-lines-drag-and-drop
---

Drag and drop is a very useful tool in applications as it can simplify a large part of the process for users. It's also a common task we delegate to other libraries which may bloat your app when you just need _a very simple implementation_ when you can use the [Drag and Drop Web API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API). **Today, I'll show you how you can do just that!**

## What we are making

This is the basic implementation we are aiming to build:

{% codepen https://codepen.io/SiddharthShyniben/pen/OJjePGv %}

That was made in just 16 lines of JavaScript!

And with a few more lines we can add a lot more bonus features! Here's a demo with some more features!

{% codepen https://codepen.io/SiddharthShyniben/pen/xxLNJxj %}

Play around with it, you will see that we can

- Drop elements only in certain places
- Style the element in which we are dropping
- Style the original copy of the dragged element
- (With a little trickery) even style the dragged element!

All this with just 30 lines of code!

It works on almost all desktop browsers with partial support all the way back to IE 6(!) which should be enough for this to work, but it doesn't work on some mobile browsers.

You can see the up-to-date CanIUse data here:

![Data on support for the drag and drop feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/dragndrop.jpg)

Dealing with libraries for this very basic functionality has been a pain for me, and to save you the trouble I thought I'd document the process here!

## HTML structure

### Places to drag into

You need some drop targets to be able to drag something into them right? We can add these using regular divs:

```html
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>

```

> **Note:** I'll be referring to the places we can drop into as drop targets in this post

You can add as many of them wherever you like, as long as an element has the `drop` class we **will** be able to drop into them.

We can also add some basic styles for them to look nice.

```css
* {
    box-sizing: border-box;
    font-family: sans-serif;
}

.drop {
    width: 220px;
    height: 45px;
    background: #2563EB;
    margin-bottom: 10px;
    padding: 10px;
    border-radius: 3px;
}

```

### The element to drag

For an element to be draggable, we need, well, an element! We can place the element in one of the drop targets we made before. This is how it should look like

```html
<div class='drop'>
    <div id='drag' draggable='true' ondragstart='event.dataTransfer.setData('text/plain', null)'>
        Drag me!
    </div>
</div>
<div class='drop'></div>
<div class='drop'></div>
<div class='drop'></div>

```

Notice how we also set the `draggable` attribute to true. Every draggable element needs to have the `draggable` attribute set for it to be draggable.

Also, not every element can be dragged even if the `draggable` attribute is set. We need to explicitly say that the element is draggable by listening to the `dragstart` event in the HTML. There we are setting `null` as we don't have any data to share and we are setting the data type `text/plain`.

We can (again) also add some basic styles for them to look nice.

```css
#drag {
    width: 200px;
    height: 25px;
    border-radius: 3px;
    background: black;
    color: white;
    display: grid;
    align-items: center;
    justify-content: center;
}

```

Note that as long as an element has the `draggable` attribute set to `true` and the drop targets have the `drop` class, the below code should work everywhere

## The minimal implementation

For our drag and drop to be functional, we just need 3 different event listeners. Everything else is a bonus.

First, we need to store the element we are dragging. We can do this by listening to the `dragstart` event.

```js
let dragged;

document.addEventListener('dragstart', event => {
    dragged = event.target;
}, false)

```

Whenever an element is dragged, this will store the dragged element in a variable.

Next, we can listen to drop events so we can drop elements.

```js
document.addEventListener('drop', event => {
    // Prevent default behaviour (sometimes opening a link)
    event.preventDefault();

    if (event.target.className === 'drop') {
        dragged.parentNode.removeChild(dragged);
        event.target.appendChild(dragged);
    }
}, false)

```

Whenever we drop an element, if the element is a drop target (has the `drop` class) we will append the dragged element to the drop target.

We're almost done, but we need to do one more thing to make this work.

By default, dragging elements does nothing, so to prevent the default behavior we need to call `event.preventDefault` whenever we drag over the drop target.

This is easy to achieve with a oneliner:

```js
document.addEventListener('dragover', event => event.preventDefault(), false);

```

That's it! In 16 lines we have functional drag and drop!

{% codepen https://codepen.io/SiddharthShyniben/pen/OJjePGv %}

Here's a video of it in action:

![Minimal drag and drop](https://cdn.hashnode.com/res/hashnode/image/upload/v1637759563871/Jbnu70TS1.gif)

## Adding more features

Even if this drag and drop _works_, it's not very nice. It doesn't seem very "natural". Luckily, in a few lines of code, we can make this drag and drop even better!

### Styling the original dragged element

Whenever we drag an element, the original copy of the element doesn't change its style. It would look better if we could add a different style to these dragged elements, like making them transparent to show that it is being dragged.

This is very easy to do. Just add the styles in the `dragstart` event listener.

```js
document.addEventListener('dragstart', event => {
    // ...

    event.target.style.opacity = 0.5;
    // add more styles as you like...

    // ...
});

```

But we also need to reset the style once we finish dragging. We can do that by listening to `dragend`:

```js
document.addeventListener('dragend', event => event.target.style.opacity = '', false)

```

## Styling the drop targets

We can also style the drop target by listening to the `dragenter` event:

```js
document.addEventListener('dragenter', event => {
    if (event.target.className === 'drop') event.target.style.background = '#2c41cc';
}, false)

```

Once again, we need to reset the styles once we leave the element. We can do that by listening to `dragleave`:

```js
document.addEventListener('dragleave', event => {
    if (event.target.className === 'drop') event.target.style.background = '';
}, false)

```

We also need to reset the styles once we drop the event. We can edit the `drop` event to achieve this.

```js
document.addEventListener('drop', event => {
    // ...

    if (event.target.className === 'drop') {
        event.target.style.background = '';
    //...
})

```

### Styling the dragged copy

With a bit of trickery, we can style the dragged copy too! Maybe we can rotate the element a bit to make it a bit more natural.

We can do this by styling the original copy and immediately undoing those styles in the `dragstart` event so that the users don't see it.

```js
listen('dragstart', event => {
    // ...

    event.target.style.transform = 'rotate(-2deg)';
    setTimeout(() => event.target.style.transform = '', 1);
})

```

Now the dragged copy will appear to be rotated when we are dragging it!

You now have a fully functioning drag and drop implementation!

{% codepen https://codepen.io/SiddharthShyniben/pen/xxLNJxj %}

Here's a video of it in action:

![Complete drag and drop.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637760011123/xOQLondbk.gif)

[Here's a Gist with all the source code for reference](https://gist.github.com/SiddharthShyniben/cd35cf13929e93b4210ffae72b57f986)

## Conclusion

We took a task for which we very commonly delegate to libraries and implemented it ourselves, with surprisingly little code.

I hope this opens your eyes to how much you can do with just vanilla JS. You don't need libraries every time.

Have you ever tried implementing drag and drop on your own? Share in the comments!