Implementing a minimal dashboard with drag and drop in JavaScript

In this article we’ll demonstrate the implementation of a minimal dashboard where the added widgets can be dragged across the visual grid.

The Theory

To be draggable with the native drag and drop API, an element must have the draggable attribute set to true. When dragging starts, the dragstart event is triggered. A key concept to clarify right away: this event, along with the others we’ll see, is handled on the parent element of the dragged element.

So event.target contains a DOM reference to the element being dragged. At the beginning of the drag, we can mark this element with a special CSS class, which we’ll then remove once dragging ends. The relevant events are:

  • dragstart: the drag operation begins on the chosen element, accessible via the target property of the event object; event.dataTransfer.effectAllowed lets us specify the visual effect to use.
  • dragover: triggered when the dragged element is over another element.
  • dragend: triggered when the drag operation has ended.
  • drop: triggered when the chosen element is released.

However, these events only control the transfer and release phases. To actually move the chosen element into the target area at the DOM level, we need to:

  1. Mark the chosen element with a special CSS class when the operation begins.
  2. Ignore or block intermediate events.
  3. On the drop event, select the chosen element, clone it, and append it to the target container, removing it from the DOM in the same operation. Since the cloned element still has the special CSS class, we must remove it so there’s only one marked element per operation.

The Code

 function dragWidgets(wrapper = null) {
    if (!wrapper) {
      return;
    }
    const containers = wrapper.querySelectorAll('.dashboard-content-area');
    wrapper.addEventListener('dragstart', (e) => {
        
        if (e.target && e.target.classList.contains('dashboard-widget')) {
          e.target.classList.add('dragged');
          e.dataTransfer.effectAllowed = 'move';
        }
      });
    for (const container of containers) {
      

      container.addEventListener('dragend', (e) => {
        e.preventDefault();
      });

      container.addEventListener('dragover', (e) => {
        e.preventDefault();
      });

      container.addEventListener('drop', (e) => {
        const draggedEl = document.querySelector('.dragged');
        if (draggedEl) {
          const copy = draggedEl.cloneNode(true);
          copy.classList.remove('dragged');
          container.appendChild(copy);
          draggedEl.remove();
        }
        e.preventDefault();
      });
    }
  }

Demo

JavaScript Dashboard

Conclusion

This type of layout allows us to leverage JavaScript’s native drag and drop API to implement a key feature of a graphical user interface.

Back to top