← Back toDrag and drop in React

Build a drop file indicator

Written byPhuoc Nguyen
Created
28 Nov, 2023
The drop file indicator is a crucial feature that allows users to upload files by dragging and dropping them into a designated area. This intuitive and seamless experience eliminates the need for users to navigate through several pages or windows to upload files.
Web applications that require frequent file uploads benefit greatly from drop file indicators as they reduce friction and cognitive load associated with uploading files. You've probably seen this component in action when dropping a file into an area, and an overlay appears on top of the drop target to indicate that you're dropping a file.
Drop file indicators are widely used in email clients, cloud storage services, and project management tools. For instance, when composing an email, users can drag and drop attachments onto the email body to add them as attachments. An indicator that shows where the user can drop the attachment can reduce confusion and ensure that the attachment is added correctly.
Google Drive and Dropbox allow users to upload files by dragging and dropping them from their local machine. A drop file indicator helps users understand where they should drop their files to initiate the upload process.
Project management tools like Trello and Asana often have a feature that allows users to attach files to tasks or projects by dragging and dropping them onto the task card. A drop file indicator ensures that the user knows where they can place their files for upload.
In this post, we'll learn how to create a drop file indicator with React. With this tool, we can simplify the file upload process and improve usability for end-users.

Determining if users are dragging files

Let's create a `DropIndicator` component - a React functional component that allows users to drag and drop files onto a specific area. To handle drag events, we'll use the `useRef` hook to create a reference to the container element.
DropIndicator.tsx
const containerRef = React.useRef();
return (
<div
ref={containerRef}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
...
</div>
);
The `DropIndicator` component needs four event handlers to provide a smooth drag and drop experience. These events are `drop`, `dragover`, `dragenter`, and `dragleave`.
When a user drags a file over the designated area, the `dragover` event is fired repeatedly. The component handles this event by calling the `preventDefault()` method. This prevents the browser from opening or displaying the dragged file, which is not what we want.
ts
const handleDragOver = (e: DragEvent): void => {
e.preventDefault();
};
The `dragenter` event happens when a user drags a file into the target area of another element. When this happens, we increase the value of `dragCount` to keep track of how many times an element has been dragged into the target area. If there are no files currently being dragged over the container (which is indicated by a count of 1), we set `isDragging` to true.
ts
const handleDragEnter = (e: DragEvent): void => {
e.preventDefault();
dragCount.current += 1;
if (dragCount.current <= 1) {
setDragging(true);
}
};
In this example, we're using the `useRef()` hook to keep track of how many times the drag event has been triggered. Additionally, we're using an internal state called `isDragging` to determine whether or not users are currently dragging a file.
ts
const dragCount = React.useRef(0);
const [isDragging, setDragging] = React.useState(false);
The `dragleave` event is triggered when a user drags a file out of a container element, and it means that the element is leaving another element's target area. When this happens, the value of the `dragCount` variable decreases. If there are no more items being dragged over after decreasing the count, then the state of `isDragging` is set back to `false`.
ts
const handleDragLeave = (e: DragEvent): void => {
e.preventDefault();
dragCount.current -= 1;
if (dragCount.current <= 0) {
setDragging(false);
}
};
Once a user drops a file onto the container element, the `drop` event is fired. We prevent its default behavior and reset all values to their initial state. For instance, we set the state of `isDragging` to false, indicating that no file is being dragged.
ts
const handleDrop = (e: DragEvent): void => {
e.preventDefault();
setDragging(false);
dragCount.current = 0;
// Do something with files ...
};

Displaying the indicator

When rendering, if there are files being dragged over the container, it will display the message "Drag and drop a file here". If there are no files being dragged, it will display a button that says "Upload a file". By clicking this button, a standard file upload dialog box will open.
tsx
<div className={`indicator ${isDragging ? 'indicator__dragging' : ''}`}>
{
isDragging ? 'Drag and drop a file here' : (
<button>Upload a file</button>
)
}
</div>
When a user drags files over the target area, we can customize the look and feel of the indicator. For instance, we can add a dashed border around the container element to show that the user can drop their files in this spot.
In our CSS stylesheet, we set the border color to light gray, and make it dashed using `border-style: dashed`. When the user drags a file out of the container or drops it onto it, the `isDragging` state is updated, and we remove this class from the element's class list.
You can adjust the styles to fit your design.
css
.indicator__dragging {
border: 2px dashed rgb(203 213 225);
}
Take a look at the demo below and give it a try by dragging and dropping a file onto it. Just a heads up: the main button is only for demonstration purposes and won't actually open a dialog box for you to choose a file.

Conclusion

In summary, if your web application involves file uploads, a drop file indicator is a must-have feature. It simplifies the process for users, making file uploads more intuitive and seamless.
In this post, we've learned how to create a drop file indicator component with React using event handlers like `dragover`, `dragenter`, `dragleave`, and `drop`. We've also explored how to use the `useRef()` hook to keep track of how many times the drag event has been triggered within our functional component.
By incorporating the drop file indicator into your web application, you can significantly improve the user experience by streamlining the file upload process.
If you found this post helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

Questions? 🙋

Do you have any questions about front-end development? If so, feel free to create a new issue on GitHub using the button below. I'm happy to help with any topic you'd like to learn more about, even beyond what's covered in this post.
While I have a long list of upcoming topics, I'm always eager to prioritize your questions and ideas for future content. Let's learn and grow together! Sharing knowledge is the best way to elevate ourselves 🥷.
Ask me questions

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn