April 24, 2017 Pierre-Louis Le Portz 6 min read

Drag & drop has become such a common feature on the web that people think it's a no-brainer for developers. A few months back, a client told me: "How can it be that hard, it's all over the internet!" and at that time I had no idea how to implement it. If you want to learn how it's done, you are in the right place. Keep calm and read along!

Choose your technical approach

There are plenty open-source drag & drop libraries on the Internet. My advice is not to rush into the first library you find! You might spend a few days trying to tweak it only to realize it does not meet your project requirements.

That's why the first part of this article is dedicated to drag & drop with HTML5, a sturdy and customizable solution which does not require you to install any external library. In the second part I will look into Dragula, a straightforward solution for reordering blocks on a web page, which comes with nice style features.

The demos are available here:

A Sturdy Solution: Drag & Drop with HTML5 Attributes

Say you have two elements in your view: a draggable item and a drop zone.

< div > DRAGGABLE ITEM </ div > < div > DROP ZONE </ div >

To make the first element draggable, add the draggable attribute:

< div draggable = " true " > DRAGGABLE ITEM </ div >

By default nothing can be dropped into an element so the drop zone is not operational yet. Use the ondragover attribute to enable this behaviour:

< div ondragover = " allowDrop(event) " > DROP ZONE </ div > < script > allowDrop = ( event ) => { event . preventDefault ( ) ; } </ script >

Use the ondrop attribute to decide what to do when the item is dropped on the zone. In the example below I log a message in the console:

< div ondragover = " allowDrop(event) " ondrop = " handleDrop() " > DROP ZONE </ div > < script > allowDrop = ( event ) => { event . preventDefault ( ) ; } handleDrop = ( ) => { console . log ( 'You dropped something!' ) ; } </ script >

That's it! You now have basic drag & drop on your web page!

You can now add some extra features with the ondragstart , ondragenter and ondragleave attributes. For instance, a nice feature with ondragenter and ondragleave would be to highlight the drop zone by adding and removing a custom css class of your choice (named dragging-over in the example below). Here is the full code:

< div draggable = " true " ondragstart = " handleDragStart() " > DRAGGABLE ITEM </ div > < div ondragover = " allowDrop(event) " ondrop = " handleDrop() " ondragenter = " colorize(this) " ondragleave = " uncolorize(this) " > DROP ZONE </ div > < script > allowDrop = ( event ) => { event . preventDefault ( ) ; } handleDragStart = ( ) => { console . log ( 'Started dragging' ) ; } colorize = ( element ) => { console . log ( 'Entered the drop zone' ) ; element . classList . add ( 'dragging-over' ) ; } uncolorize = ( element ) => { console . log ( 'Left the drop zone' ) ; element . classList . remove ( 'dragging-over' ) ; } handleDrop = ( ) => { console . log ( 'You dropped something!' ) ; } </ script >

Sometimes you don't need to implement your own custom solution and a turnkey library can fit your project needs. Don't reinvent the wheel if you don't need to!

Reordering the DOM: introducing the Dragula library

Dragula lets you reorder elements of the DOM. In the following example I display the word "SMILE" and let the user move the letters around to form anagrams like "SLIME" or "MILES".

The demo is coded with React but Dragula bridges are also available for Angular 1 and Angular 2.

As I am not using Webpack or any other tool to require Dragula, I use a <script> tag in the index.html file:

< html > < head > < meta charset = " UTF-8 " /> < title > Drag & Drop - Dragula for React </ title > < link rel = " stylesheet " href = " style.css " > < link href = " bower_components/react-dragula/dist/dragula.min.css " rel = " stylesheet " type = " text/css " > </ head > < body > < div id = " anagram " > </ div > < script src = " https://unpkg.com/react@latest/dist/react.js " > </ script > < script src = " https://unpkg.com/react-dom@latest/dist/react-dom.js " > </ script > < script src = " https://unpkg.com/babel-standalone@6.15.0/babel.min.js " > </ script > < script src = " bower_components/react-dragula/dist/react-dragula.js " > </ script > </ body > </ html >

Now let's create a React component named Anagram and mount it on the div with the "anagram" id. Add a <script> tag to the body:

< script type = " text/babel " > class Anagram extends React . Component { render ( ) { return < div className = "anagram-container" > < div className = "letter-outter-container" > < div className = "letter-container" > S < / div > < / div > < div className = "letter-outter-container" > < div className = "letter-container" > M < / div > < / div > < div className = "letter-outter-container" > < div className = "letter-container" > I < / div > < / div > < div className = "letter-outter-container" > < div className = "letter-container" > L < / div > < / div > < div className = "letter-outter-container" > < div className = "letter-container" > E < / div > < / div > < / div > ; } } ; ReactDOM . render ( < Anagram / > , document . getElementById ( 'anagram' ) ) ; </ script >

The css classes letter-container and letter-outter-container are up to you. I wrapped the letter-container divs in order to get some spacing within letters without using margins because they generate glitches with Dragula. At this point I have something like this:

Finally, add the componentDidMount lifecycle method in the component and apply Dragula to the created DOM node:

componentDidMount ( ) { var container = ReactDOM . findDOMNode ( this ) ; reactDragula ( [ container ] ) ; }

And there you go! You can now reorder the letters with drag & drop. You will also notice the very cool shadow image that indicates where the dragged element would be dropped. Dragula's tagline is "Drag and Drop so simple it hurts".

HTML5 vs Dragula

The one major drawback of the HTML5 DragEvent is that it is not compatible with touch devices. If you need to implement features for smartphones or tablets, have a look at the touchstart , touchmove and touchend events. They work pretty similarly!

As for Dragula, I definitely recommend it for DOM reordering features. It's super-easy to use and once you know that glitches may occur with the margin and display: flex properties, everything should be okay.

You now have the tools to start coding pretty cool features with drag & drop! To go further you can check out the HTML Drag and Drop API, the Touch Events API and the Dragula options.