Drag & Drop Photo With Vanilla JavaScript

In this article I'm going to explain the javascript drag-and-drop events, and at the end of it we'll going to build a mini application that illustrates the events packed together into a single application and see what it looks likes.

Before we get started I want to give you some insights on drag events.

Drag Events

from developer.mozilla.org

HTML drag and drop uses the DOM event model and drag events inherited from mouse events. A typical drag operation begins when a user selects a draggable element with a mouse, moves the mouse to a droppable element and then releases the mouse. During the operations, several event types are fired and some event types might be fired many times (for example the drag and dragover event types).

All of the drag event types have an associated global event handler. Each drag event type and drag global attribute has a reference document that describes the event. The following table provides a short description of the event types.

Different Drag Events

We actually won't use the dragexit & ondrag events.

Getting started

Now let's make use of the drag events, we'll started by creating our HTML markups.

We have five boxes with the class of empty, inside one of them there is a div with the class of fill. Notice the HTML property draggable which is set to true, if we don't do it we won't be able to drag it.

And that's it for the markup, dead simple.

The CSS

  
          body{
          background: #4c4c4c;
          font-family: 'Montserrat', sans-serif;
      }


      .fill{
          background-image: url('http://source.unsplash.com/random/150x150');
          position: relative;
          height: 150px;
          width: 150px;
          top: 5px;
          left: 5px;
          cursor: pointer;
      }

      .empty{
          display: inline-block;
          height: 160px;
          width: 160px;
          margin: 10px;
          background-color: #323232;
          border-radius: 6px;
      }

      .hold {
        border-style: dashed;
      }

      .hovered{
          background: #F0F3F4;
          transition: all ease-in-out .2s;
          transform: scale(1.1);
      }

      .invisible{
          display: none;
      }

  

Understanding the CSS

For the fill & empty classes are quite straight forward we're just styling them the way we want the boxes to display. But what about the extra classes? They will be applied with the JavaScript when different events occurs

The JavaScript

We start by storing the fill and empty classes in variables.

  
    const fill = document.querySelector('.fill');
    const emptyBoxes = document.querySelectorAll('.empty');
  

The divs with the class of empty isn't one so we get all of them by using (document.querySelectorAll) and that put them all in a node, since it's a node list we have to do a for loop .

  
    for(const empty of emptyBoxes){
    empty.addEventListener('dragover', dragOver);
    empty.addEventListener('dragenter', dragEnter);
    empty.addEventListener('dragleave', dragLeave);
    empty.addEventListener('drop', dragDrop);
}

  

We looped through the emptyBoxes and the same time we added event listeners to them. Now let's add event listeners to the fill variable.

  
    fill.addEventListener('dragstart', dragStart);
    fill.addEventListener('dragend', dragEnd);

  

Now what happens when the dragStart and dragEnd events occurs? This is what we want to happen

  
    //dragStart function
    function dragStart(){
        this.className += ' hold';

        setTimeout(() => this.className = 'invisible', 0);
    }

  //dragEnd function
  function dragEnd(){
      this.className = 'fill';
  }

  

The drag functions for the emptyBoxes

  

    function dragOver(e){
        e.preventDefault();

    }

    function dragEnter(e){
        e.preventDefault();
        this.className += ' hovered';

    }

    function dragLeave(){
        this.className = 'empty';
    }

    function dragDrop(){
        this.className = 'empty';
        this.append(fill);
    }
  

Here's the final product

The transition is smoother than it shows on the screen. The software I used to record it has some issues. So normally it would transit smoothly without any issues on the browser.

Bring everything together

So basically this is what the JavaScript code would look like.

  

    const fill = document.querySelector('.fill');
    const emptyBoxes = document.querySelectorAll('.empty');


    //loop through empies

    for(const empty of emptyBoxes){
        empty.addEventListener('dragover', dragOver);
        empty.addEventListener('dragenter', dragEnter);
        empty.addEventListener('dragleave', dragLeave);
        empty.addEventListener('drop', dragDrop);
    }


      //add listener to fill
    fill.addEventListener('dragstart', dragStart);
    fill.addEventListener('dragend', dragEnd);

    //drag functions
    function dragStart(){
        this.className += ' hold';

        setTimeout(() => this.className = 'invisible', 0);
    }

    function dragEnd(){
        this.className = 'fill';
    }

    function dragOver(e){
        e.preventDefault();

    }

    function dragEnter(e){
        e.preventDefault();
        this.className += ' hovered';

    }

    function dragLeave(){
        this.className = 'empty';
    }

    function dragDrop(){
        this.className = 'empty';
        this.append(fill);
    }