0

I'm making a custom drop zone. Here is html code:

<template>
  <div
     class="dropzone"
     @drop.prevent="dropFileHandler"
     @dragover.prevent="dragOverHandler"
     @dragenter.prevent
     @dragleave="dragLeaveHandler"
     :class="{ draggedOver: isDraggedOver }"
  >
    <input
        // ...
        // ...
    />

    <label for="fileInput" class="fileLabel">
      Drop your files
      <span>or</span>
      <span class="clickText">click here to upload</span>
    </label>
  </div>
</template>

and a part of a script for the dragOverHandler function:

function dragOverHandler() {
 if (!isDraggedOver.value) {
   isDraggedOver.value = true;
  }
}

The handler simply assign true to isDraggedOver reactive value which is used to switch a class of a dropzone - white when nothing is dragged over and green when something is dragged over the dropzone.

What I don't like about this solution is that I have to use dragover event instead of dragenter (which only fires once). The reason for that is when I use dragenter with the same handler

<div
     class="dropzone"
     @drop.prevent="dropFileHandler"
     @dragover.prevent
     @dragenter.prevent="dragEnterHandler"
     @dragleave="dragLeaveHandler"
     :class="{ draggedOver: isDraggedOver }"
  >

// ...
// ...

function dragEnterHandler() {
   isDraggedOver.value = true;
}

dragging a file over any child node of dropzone (over label, for example) is counted as a dragleave event so even if hold a file over the dropzone it's not green anymore.

What do I do about this? Or dragover event is okay in this case?

P.S. off topic. I see many developers also add an invisible 1x1 px input element inside a dropzone. And then pass dropped files into it via template ref. You can see I use this technique too. I tried not to use that input and everything worked the same way. But I kept it because I'm not sure yet if it's a good practice to create a dropzone without such input element. What is it's purpose?

b3rry
  • 21
  • 5

1 Answers1

3

dragging a file over any child node of dropzone (over label, for example) is counted as a dragleave event so even if hold a file over the dropzone it's not green anymore.

to avoid this you can set pointer-events: none; on the children you don't want "stealing" the drag. keep in mind that this will also disable all pointer events on those components including clicks.

Another solution would be to have an invisible dropzone element that appears over top of the drop area whenever you get a dragover event on the body. (Absolute positioning, high z-index).

something along the lines of: https://stackoverflow.com/a/61417954/5861427

But that doesn't really get rid of dragover. That being said, I don't think using dragover is bad. I've seen many people use both dragenter and dragover at the same time to signify a start and dragleave as well as drop to signify the end of a drag (successful or not). I've been using this combo myself for quite some time and found it to be reliable.

As for the value of the input element, setting it gives assistive technologies a clear indication that a file has indeed been selected.

nezu
  • 318
  • 3
  • 11
  • thank you for a detailed answer :) I was thinking about using `pointer-events: none;` but in my case I have a clickable `span` inside the `label`. So it will make that `span` uninteractive – b3rry Feb 21 '23 at 21:29