Drag files in HTML and React without flickering

I needed something simple for my image-resizing project: the ability to drag files from the filesystem’s OS to the browser window, which will read the list of files that are dropped. This sounds to be a simple problem with simple solutions, right? Well, not so fast.

At first I thought there should be 2 main events I should consider – inspired from hover state – which are: (1) when files are dragged over the element, and (2) when it is dropped. I mean, drag and dropping sounds pretty straightforward, right?

Boy, how wrong that was. As of this writing, there are 8 different events associated with drag n drop. And we need to deal with 4 of them to create the interaction I intended:

  1. onDragEnter – triggered when the user drag over an element *
  2. onDragLeave – triggered when the user drag out of an element *
  3. onDragOver – triggered over and over when the user drag over an element. It triggers every few hundred millisecond.
  4. onDrop – triggered when the user drops something on an element.

So basically you need to listen for the onDragEnter event on an element to know when a drag event (mouse passing over an element with pushed-down button) is entering an element. I thought that was it but it comes with a catch. My element isn’t consistently detecting the drag event. Apparently the onDragEnter is triggered when the mouse enters the element, but if an element has any descendant, it triggers the onDragLeave and then another onDragEnter for every element we are at! So if you try to toggle the dragging state by depending only on those two states, you will have a bug-hunting time. Surprise!

So apparently a movement from that element to its child element triggers an onDragLeave event, and followed immediately by another onDragEnter event. See the diagram in this Smashing Magazine’s article to see an excellent explanation of how it works.

Knowing that, we just need to add a simple counter to count how many onDragEnter events has been detected. If it’s more than 0, we know that it’s still on top of the element 🙂

Consult the code on the Smashing Magazine’s article or on my github.

Happy coding!