Adding Drag & Drop to Your Web App, the Simple Way (demos)
Pierre-Louis Le Portz5 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">
<!-- Do not forget to import the Dragula style sheet -->
</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>
<!-- I use Babel to transform JSX to javascript -->
<script src="bower_components/react-dragula/dist/react-dragula.js"></script>
<!-- I previously installed react-dragula with Bower -->
</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.