Better Programming

Advice for programmers.

Follow publication

How to Implement the Drag-and-Drop of Files in React

Yelysei Lukin
Better Programming
Published in
4 min readJan 30, 2020
Photo by Claudel Rheault on Unsplash

Heyo, geeks!

When it comes to uploading files, we can, of course, easily handle it with the default <input type='file'/>. But I’m pretty sure most will agree it’s much comfier to drag and drop your files into the web page rather than searching for them in the file-dialog window.

Therefore, let’s figure out how we can easily create an area in React for the dragging and dropping of files.

Handle File Uploading

First, let’s create a basic project structure and styling.

App.js

FilesDragAndDrop.js

FilesDragAndDrop.scss

This is what we’ve got so far.

Now, let’s add some logic.

Create a ref for the drop area:

Add listeners for the drop and dragover events, and prevent their default behavior (opening the dropped file):

Basically, to get things working, we only need to check if the dropped element contains files and to pass them to our parent component.

Hurray! Our drag-and-drop component is working.

Now when we receive dropped files in the parent component, we can do whatever we need with them (e.g., pass them to some API endpoint).

But it’s definitely not exactly how we’d like our drag-and-drop component to work. So let’s make some essential improvements.

Customize Content

One of the main React best practices is the reusability of components.

That’s why it’d be better to provide content for the drag-and-drop area from a parent component. Our drag-and-drop component will serve as a wrapper, and we’ll be able to reuse it anywhere.

So instead of some hardcoded content, we’ll render the children prop inside our component:

While using the component, we need to wrap it around some custom content:

Validate File Formats and Count

Like any other input (whether it’s a number, date, or file), we may need to validate the entered data. In some cases, we should only allow the uploading of certain file formats. In other cases, we’ll need to limit the number of files that can be uploaded at a time.

While in the default <input type="file"/>, we can validate formats using the accept parameter and validate the number of files using the multiple parameter. In our custom component, we need to handle validation manually.

To implement it, let’s add new count and formats props to our component and handle them inside the handleDrop function:

That’s it! Now our component will prevent uploading files with the incorrect format or quantity.

Last but Not Least — UI/UX

Overlay on dragover

When users interact with a system, they always expect some feedback — i.e., when files are dragged over the drag-and-drop area, it’d be nice to show an overlay with a message confirming the user is doing everything right.

To handle dragging over the area, we need to do the following: Add a dragging parameter to the state, and handle dragenter and dragleave events (enable dragging when a dragged file is entering the area, and disable when it’s leaving it):

If dragging is enabled, show an overlay above the area:

When you implement it, you may notice something’s wrong:

This happens because once the dragenter event is fired, we show the overlay above the content. Therefore, the content loses drag and fires the dragleave event while the overlay catches the drag and fires the dragenter event. This causes the endless changes of the dragging flag.

But it’s pretty easy to fix. We just need to check whether the event is fired from the overlay or not. If the dragenter event isn’t fired from the overlay, we need to show it, and if the dragleave event is fired from the overlay, we need to hide it.

Add the ref for the overlay:

Then check if the event target is equal to the overlay:

Also, don’t forget to reset the dragging flag on the drop so it won’t affect the next dragging file:

Message about successful upload or validation error

The last thing we need to implement is the info message when files are successfully uploaded or when they didn’t pass the validation.

Let’s add the message parameter to our state and the function that’ll handle it:

During the render, we’ll check the message parameter and display the appropriate message, if needed.

When it’s done, we can invoke the showMessage function anywhere we need:

Here’s what we’ve created.

Conclusion

Before you start implementing your own drag-and-drop, I want to share some good news with you.

I created the npm package for this component with even more cool stuff, such as TypeScript, a file dialog window on click, text and style customization, etc.

Write a response