How to implement file upload with drag and drop in vanilla JS
I wrote about the Drag and Drop API concepts in the past.
Now I want to show how I implemented a simple file upload with drag and drop on a site I’m building.
Identify an HTML element you want people to drag their files to:
<div
class="dropzone"
ondragover=`dragOverHandler(event)`
ondragleave=`dragLeaveHandler(event)`
ondrop=`dropHandler(event)`
>
...
</div>
ondragover
is fired when people are dragging a file on the element. We can use this to add some style, for example a dashed border.
ondragleave
is the opposite, when we exit the drop area.
I used this JS to add a dragging_over
class to the element, and style it with CSS:
function dragOverHandler(event) {
event.preventDefault();
const dropzone = document.querySelector('#dropzone');
dropzone.classList.add('dragging_over');
}
function dragLeaveHandler(event) {
event.preventDefault();
const dropzone = document.querySelector('#dropzone');
dropzone.classList.remove('dragging_over');
}
#dropzone.dragging_over {
border: 2px dashed #fff;
background-color: #666;
}
ondrop
is fired when the file (or multiple files!) is dropped on the area.
That’s where the action happens.
I gather the files, check they’re images (I only want images in this example), and POST the data to /api/upload
:
async function dropHandler(event) {
event.preventDefault()
const endpoint = `/api/upload`
if (event.dataTransfer.items) {
const formData = new FormData()
formData.append('action', 'upload')
for (let item of event.dataTransfer.items) {
if (item.kind === 'file') {
const file = item.getAsFile()
if (file) {
//I only want images
if (!file.type.match('image.*')) {
alert('only images supported')
return
}
formData.append('files', file)
}
}
}
try {
const response = await fetch(endpoint, {
method: 'POST',
body: formData,
})
if (response.ok) {
console.log('File upload successful')
} else {
console.error('File upload failed', response)
}
} catch (error) {
console.error('Error uploading file', error)
}
}
}
How to handle that server-side depends on your server.
With Astro I got the data using:
const formData = await Astro.request.formData()
console.log(formData.getAll('files'))
→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter
→ JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025