Step by Step: Custom drag & drop upload component in Vuetify (Vue 2)

A few weeks ago I had to implement a drag and drop upload component for a project I was working on. Vuetify only provides a component that works by clicking to upload, called file input, and to be honest the user interface is not so great (you can check it here or check the image below 👇).

The file input component provided by Vuetify as of version v2.3.13
User interface of the completed component

Creating the upload component

The first thing in our development will be to create the upload component and develop the user interface. Start by creating a new Vue component called Upload. Your code now should look like this 👇

Note: The max-width prop is set to 450px which I find to be a good width for my component.

Displaying the component

Before starting to implement any functionality for dragging & dropping files, clicking to select files or uploading, we need to be able to display our component so that we can test as we code.

Improving the UI and UX

Right now our component is just an empty white box with two buttons at the bottom right corner. That’s not ideal. Our users won’t know how to upload their files. Let’s add some text to guide them. Feel free to change the design to suit your preferences.

Adding the drag and drop functionality

To implement the drag and drop functionality of our component, we will make use of the Drag and Drop API provided. If you are not familiar with the api please spend a few minutes understanding how it works and the drag events and interfaces it offers. In our case, we will only use these events:
1. @drop : To detect when the items are dropped in our drop zone area
2. @dragover: To detect when the items are dragged over our drop zone
3. @dragenter: To detect when the items enter our drop zone
4. @dragleave: To detect when the items leave our drop zone

On Drop event

Now it’s time to retrieve the files uploaded by the user. As of now when the user drops the files in the drop zone, we only set the dragover variable to false. Let’s implement a onDrop method to add more functionality.

Note: The this.$store.dispatch command is from Vuex. It is used to trigger an action in my notification system. In your case you can replace it with whatever you want to let the user know that they can’t upload multiple files.

Resetting the uploadedFiles

There are two cases where we will need to reset the uploadedFiles variable. The first one is when the user closes the dialog box. In the case that we don’t remove the uploaded files when the dialog box closes, if the user opens the upload box again before reloading the web app, it will still contain the previous files that the user cancelled. So, in our closeDialog method we add

this.uploadedFiles = [];
if (this.uploadedFiles.length > 0) this.uploadedFiles = [];

Displaying the uploaded files

Now that our user can drag and drop files into our upload component, we can improve our user experience by displaying the files that have been uploaded. We will do this by using the v-virtual-scroll and the v-list-item components. We use the scroll component to be able to display all the uploaded files without having to worry how much our dialog box we expand. (In the case that your upload component is intended to be used only for uploading less than 3 files, you can skip the v-virtual-scroll component). Check the code below 👇. An explanation is following right after so if you don’t understand what’s going on… no need to panick!


Sending the uploaded files to the parent component

Finally, to keep our upload component as simple as possible, instead of processing the uploaded files here, we will pass them to the parent component. This will be done by using a custom event called files uploaded. So when our upload icon is clicked we will call a submit method and we will:
1. Check if there are any uploaded files to submit
2. Display an error notification if there aren’t and exit
3.Emit them to the parent component using the uploadedFiles event
4. Close the dialog box

Final Code
<Upload :dialog.sync="uploadDialog" :multiple="true" @filesUploaded="processUpload($event)"

Bonus: Adding the click to upload functionality

To be continued next week…

FullStack Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store