

Ask HN: Current best practice for drag-and-drop? - couchand

I&#x27;m working on an application that makes heavy use of in-app drag-and-drop to categorize and update data.  We aren&#x27;t using the DnD for sorting or arbitrary item placement, nor do we support dropping files or other media for upload.  We simply need to be able to drag a type of element and handle hovering and dropping on others of that type as well as their container.  We also only need to support Firefox and Chrome.<p>Originally it was built with HTML5 drag-and-drop, but we&#x27;ve started to see many issues, specifically in Chrome.  For instance, previously we got a ghost image of the element for free in both Firefox and Chrome, but recently Chrome has reverted to a little gray box with the element text.  We could use setDragImage, but since we&#x27;re dragging plain old DOM elements that seems excessive.  Chrome also seems to treat the dragEnter events strangely, making nested element hover handling difficult.<p>We could potentially implement a custom solution (the front-end is React, so it wouldn&#x27;t be too hard) but that also seems excessive.<p>I&#x27;m about to add a dependency on jQuery and jQuery UI just to allow the use of their bulletproof Draggable and Droppable elements.  Somehow that feels dirty.  Is there a good, modern way to allow us to drag regular DOM elements and handle the hover and drop events?  It doesn&#x27;t seem like it should be this hard.
======
callum85
From experience writing an app with loads of complex DnD, I strongly recommend
giving up on DnD libraries if you are doing anything beyond some generic
sortable list thing. You will never get the library to do what you want it to
do, and even if you get close, the performance will be fucking abysmal, for
reasons that become obvious when you've programmed your first DnD interaction
by hand. It's just not something a library can reasonably handle, because to
cover multiple use cases they have to put loads of conditional logic inside a
mousemove listener, which kills performance. DnD interactions are very
application-specific; to me the term DnD refers to a class of problems and a
corresponding skill set, not a feature that you can delegate away. And as you
have discovered, the HTML5 DnD API is a pile of shit.

Do not fear making your own drag interactions from raw mouse events. I avoided
it for ages, then discovered it is easier than I expected, and satisfying
because what you produce is so much better quality. It's just combinations of
mousedown, mousemove, mouseenter, mouseleave, and mouseup, and the confidence
to attach/detach listeners for those events on the fly during the interaction.
Also by thinking about the whole event sequence on a lower level you will
often realise a better way to design the UX of the interaction.

~~~
couchand
Thanks for the support. Eventually I think this is the way we'll go. For the
time being I'm putting up with dropping in jQuery UI, but I think my next big
project will be a few React mixins for UI interactions like this.

~~~
callum85
My comment earlier was a bit strong; there are obviously cases when you just
need to get the job done, and if jQuery UI covers your use case with an
acceptable perf hit then go with it.

If you want a halfway house, I've just remembered this little jQuery plugin,
not well known at all, but it is the best thing available:

[http://threedubmedia.com/code/event/drag](http://threedubmedia.com/code/event/drag)

For me this plugin was a bridge between using DnD libraries and writing raw
mouse listeners. It basically just fires off events at key points during a
drag sequence, and it's up to you to update element styles to move them
around... ie, you can't see anything physically happening on the page unless
you update the DOM yourself (not difficult). It's basically sugar around mouse
events to make them a lot less intimidating, eg, on each move it gives you the
mouse position relative to wherever the drag started, so you don't have to
keep track of this yourself.

Compared to any regular DnD library, it's better performing and miles more
flexible. It's almost as good as doing it with raw mouse events. Look at the
demos and view the code, they are impressive. It's old though. Hope it still
works with modern jQuery.

------
aikah
Use a well tested library,even if it means extra load.The reason for this is
DnD apis are a nightmare that will work on 90% of the devices and browsers but
not on the rest. Trust libraries that are well tested over a wide range of
browsers.

> I'm about to add a dependency on jQuery and jQuery UI just to allow the use
> of their bulletproof Draggable and Droppable elements. Somehow that feels
> dirty.

What feels even more dirty is a UI that doesnt work properly across
browsers.Better have a solid UI rather than thinking using jQuery == DIRTY.

~~~
couchand
As I said, we don't need to support anything other than Firefox and Chrome.
It's an internal app, we know everyone's on modern versions.

And as I mentioned in another comment, jQuery itself isn't dirty, but adding a
dependency on a swiss army knife library for just one feature does seem dirty.

------
_mayo
The bulletproof way would probably be to use a library to handle drag and
drop. If you're not wanting to use jQuery UI just for DnD functionality, there
are a couple libraries that do drag and drop exclusively.

1\.
[http://gtramontina.github.io/draggable.js/](http://gtramontina.github.io/draggable.js/)
2\.
[http://kbjr.github.io/DragDrop/index.html](http://kbjr.github.io/DragDrop/index.html)

~~~
couchand
We looked at both of these libraries and it seems neither supports hover and
drop events, so it seems like the front runner is still jQuery UI.

------
spb
FYI, unlike most new HTML5 standards which were discussed in the WHATWG list
and added to the standard based on developers' needs, "HTML5" DnD is a
standardization of the bizarre implementation of Drag and Drop used by some
web pages after Microsoft introduced as part of Internet Explorer 5 in 1999.
Don't expect it to be a sane foundation for what you want to do.

------
Chris_Newton
I agree with everyone recommending a tried and tested library for this.

Even with jQuery and jQuery UI, I see a few bugs and inconsistencies across
browsers from time to time. However, you only have to look at the bug trackers
for those projects to see how many more issues they have already resolved in
this area.

I’m all for keeping things light and avoiding _unnecessary_ dependencies on
external libraries, but this is one of those issues where you’d be mad to try
and get everything working properly yourself. This is one of the nastiest,
most edge-case-ridden areas of front-end web development today, and you surely
have better things to do with your time than fix every browser oddity one by
one.

------
Piskvorrr
DOM support is broken, especially when you need cross-browser compatibility.
Guess what jQuery was built to solve?

In other words, do not worry - it is not dirty, it is exactly the purpose of
jQuery.

------
lbotos
Oh! This might be the best spot to ask. I'm trying to build a web app (ipad
kiosk) that has drag and drop and scrolling. The code works perfectly on
desktop w/ trackpad because scroll and click are two different actions. Mobile
it looks like I have to re-write the scrolling logic because there are only
touch events exposed? Is there another way?

I'm currently trying JQUI with touchpunch and have considered hammer.js.
Anyone have experience with scrolling and dnd on mobile?

~~~
chrisBob
This is trivial in a native iOS app: you just look for two touches and call
that scrolling. Does the framework you are working with expose all of the
touch events?

~~~
lbotos
It could. So you are saying two fingers for scroll then, yes? I'll try that.

~~~
chrisBob
It is actually my trackpad not the iPad that uses two finger scroll. I assumed
they were the same, and I guess I don't really notice how I scroll on the
iPad. I am sure a two-finger scroll will work, but it is not the native
recommendation like I though.

The native iOS answer is actually if the finger is static for a certain time
interval then it is a click, but if it begins moving immediately then it is a
scroll (swipe).

------
michaelmcmillan
I suggest you check out how Wordpress does this in the menu-settings. They
support nested dropping and it's pretty smooth in both Firefox and Chrome.

------
lightblade
I was working on a blog post on implementing drag and drop using functional
reactive programming (FRP) with bacon.js. Your question just pushed me to
finish it :)

Here it is.

[http://www.codingupfengshui.io/functional-reactive-
programmi...](http://www.codingupfengshui.io/functional-reactive-programming-
with-baconjs-part4)

------
cjjuice
It is not dirty, jQuery and jQuery UI have been tried and tested. I wouldn't
reinvent the wheel here unless you need to.

~~~
couchand
Don't get me wrong, I love jQuery. What's dirty about it is including the
whole library when all we really need is UI's Draggable and Droppable. jQuery
UI does have a custom download builder, so that's good.

~~~
cjjuice
yeah I would just include the elements of JQuery UI you need. I just
implemented a drag to cart feature on an site I am working on and it works
great.

~~~
MalcolmDiggs
My thoughts exactly. Just use the download builder
([http://jqueryui.com/download/](http://jqueryui.com/download/)) to choose the
features you need a la carte.

------
bpierre
I started a small module to do that without any dependency:
[https://github.com/bpierre/minidrag#minidrag-](https://github.com/bpierre/minidrag#minidrag-)

------
cientifico
Same problem, also working with react. Setting react to work with this
libraries result in more effort than writing it manually.

~~~
couchand
No kidding. If you're planning on using jQuery UI, do it in
`componentDidMount` and add this to your Draggable options:

    
    
               helper: ->                                                   
                 el = jQuery this                                           
                   .clone()                                                 
                   .removeAttr "id"                                         
                                                                            
                 el.find "*"                                                
                   .andSelf()                                               
                   .removeAttr "data-reactid"                               
                                                                            
                 el

------
leo_santagada
There are libs on github just about html5 DnD... When I have the time I will
test them to remove jquery-ui from my projects.

------
anvarik
Have you tried dropzonejs? Works pretty fine, one can even drag & drop folders
of folders(chrome only)

