# File upload with drag and drop in vanilla JavaScript

> Learn how to build file upload with drag and drop in vanilla JavaScript using the ondragover, ondragleave, and ondrop events, then POST the files as FormData.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2023-12-21 | Topics: [Web Platform](https://flaviocopes.com/tags/platform/), [JavaScript](https://flaviocopes.com/tags/js/) | Canonical: https://flaviocopes.com/how-to-implement-file-upload-with-drag-and-drop-in-vanilla-js/

I wrote about the [Drag and Drop API](https://flaviocopes.com/drag-and-drop/) 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:

```javascript
<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:

```javascript
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');
}
```

```css
#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`:

```javascript
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](https://flaviocopes.com/astro-introduction/) I got the data using:

```javascript
const formData = await Astro.request.formData()

console.log(formData.getAll('files'))
```
