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 20 books to help you become a better developer:
- JavaScript Handbook
- TypeScript Handbook
- CSS Handbook
- Node.js Handbook
- Astro Handbook
- HTML Handbook
- Next.js Pages Router Handbook
- Alpine.js Handbook
- HTMX Handbook
- React Handbook
- SQL Handbook
- Git Cheat Sheet
- Laravel Handbook
- Express Handbook
- Swift Handbook
- Go Handbook
- PHP Handbook
- Python Handbook
- Linux/Mac CLI Commands Handbook
- C Handbook