> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# Drag-and-drop uploads in React (video tutorial)

[githublink]: https://github.com/cloudinary-community/cloudinary-examples/tree/main/examples/react-drag-drop-upload

## Overview

Learn how to implement drag-and-drop uploads to Cloudinary in your React app using the `react-dropzone` library.

## Video tutorial

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: :title=View the code

You can find the code from this tutorial in [GitHub][githublink].
## Tutorial contents
This tutorial presents the following topics. Click a timestamp to jump to that part of the video.
### Introduction to file upload in React
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=0 :sec=12 :player=cld} | The traditional way to select files on websites is using a file picker input element. However, to achieve drag-and-drop functionality, you can use the browser's drag-and-drop API or a library like `react-dropzone`, which simplifies this process. This tutorial demonstrates how to set up `react-dropzone`, import its component, and use the `useDropzone` hook with an `onDrop` callback function to handle selected files and preview the selected image.
|

### Setting up drag-and-drop with `react-dropzone` 
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=0 :sec=56 :player=cld} | Ensure your React application is set up, then install `react-dropzone` with `npm install react-dropzone`. Import the `useDropzone` hook by adding `import { useDropzone } from "react-dropzone"`. Set up the `onDrop` callback to log selected files, and destructure properties and methods like `getRootProps` and `acceptedFiles` to manage drag-and-drop actions.
|

```react
import { useCallback, useState } from "react"
import { useDropzone } from "react-dropzone"
import "./App.css"

export default function MyDropzone() {
  const [dataURL, setDataURL] = useState(null)
  const [uploadedURL, setUploadedURL] = useState(null)

  const onDrop = useCallback(acceptedFiles => {
    acceptedFiles.forEach(file => {
      const reader = new FileReader()
      reader.onabort = () => console.log("file reading was aborted")
      reader.onerror = () => console.log("file reading has failed")
      reader.onload = () => {
        const binaryStr = reader.result
        setDataURL(binaryStr)
      }
      reader.readAsDataURL(file)
    })
  }, [])

  const {
    getRootProps,
    acceptedFiles,
    getInputProps,
    isDragActive,
  } = useDropzone({ onDrop })
```

### Spreading `react-dropzone` props in a `<div>`
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=22 :player=cld} | Spread the props from `getRootProps()` and `getInputProps()` onto the `<div>` to make it handle drag-and-drop events.
|

```html
<div className="drop-zone" {...getRootProps()}>
    <input {...getInputProps()} />
```

### Accessing selected files
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=29 :player=cld} | Use `acceptedFiles` to access the array of selected files. Try logging the first selected file with `console.log` to see it in action.
|

```react
  const {
    getRootProps,
    acceptedFiles,
    getInputProps,
    isDragActive,
  } = useDropzone({ onDrop })

  const selectedFile = acceptedFiles[0]
  console.log(selectedFile)
```

### Setting state for data URL
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=47 :player=cld} | In the `onDrop` function, loop through the selected files (in this example, just one file). Use the `FileReader` API to read the file and listen for the `onload` event. Once the file has been read, set the file's `dataURL` as a state variable to display an image preview.
|

```react
export default function MyDropzone() {
  const [dataURL, setDataURL] = useState(null)
  const [uploadedURL, setUploadedURL] = useState(null)

  const onDrop = useCallback(acceptedFiles => {
    acceptedFiles.forEach(file => {
      const reader = new FileReader()
      reader.onabort = () => console.log("file reading was aborted")
      reader.onerror = () => console.log("file reading has failed")
      reader.onload = () => {
        const binaryStr = reader.result
        setDataURL(binaryStr)
      }
      reader.readAsDataURL(file)
    })
  }, [])
```
### Implementing visual feedback for drag-and-drop
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=2 :sec=05 :player=cld} | Implement visual feedback by checking `isDragActive`, which becomes `true` when a file is being dragged over the drop zone. Use this state to show a message or overlay, and if `dataURL` is not `null`, display a preview of the selected image along with options to upload or cancel. The buttons displayed on the preview provide a way to either cancel the action or upload the selected image, triggering the [uploadImage](#creating_the_uploadimage_function) function.
|

```react
  return (
    <div className="container">
      <div className="zone">
        {dataURL ? (
          <div className="selected">
            <img src={dataURL} />
            <div className="actions">
              {uploadedURL ? (
                <span className="uploaded-txt">Uploaded!</span>
              ) : (
                <button
                  onClick={uploadImage}
                  className="upload-btn"
                >
                  Upload
                </button>
              )}
              <button
                onClick={() => setDataURL(null)}
                className="cancel-btn"
              >
                Cancel
              </button>
            </div>
          </div>
        ) 
        <div className="drop-zone" {...getRootProps()}>
            <input {...getInputProps()} />
            {isDragActive ? (
              <div className="drop-files">
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  viewBox="0 0 24 24"
                  height="50"
                  width="50"
                  fill="currentColor"
                >
                  <path d="M1 14.5C1 12.1716 2.22429 10.1291 4.06426 8.9812C4.56469 5.044 7.92686 2 12 2C16.0731 2 19.4353 5.044 19.9357 8.9812C21.7757 10.1291 23 12.1716 23 14.5C23 17.9216 20.3562 20.7257 17 20.9811L7 21C3.64378 20.7257 1 17.9216 1 14.5ZM16.8483 18.9868C19.1817 18.8093 21 16.8561 21 14.5C21 12.927 20.1884 11.4962 18.8771 10.6781L18.0714 10.1754L17.9517 9.23338C17.5735 6.25803 15.0288 4 12 4C8.97116 4 6.42647 6.25803 6.0483 9.23338L5.92856 10.1754L5.12288 10.6781C3.81156 11.4962 3 12.927 3 14.5C3 16.8561 4.81833 18.8093 7.1517 18.9868L7.325 19H16.675L16.8483 18.9868ZM13 13V17H11V13H8L12 8L16 13H13Z"></path>
                </svg>
              </div>
            ) : (
              <div className="drag-files">
                Drop your files here or click to browse
              </div>
            )}
          </div>
        )}
      </div>
```

### Setting Up Cloudinary for file uploads
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=3 :sec=07 :player=cld} | To upload files to Cloudinary, you can use various methods. This tutorial shows how to use the [upload](image_upload_api_reference#upload) endpoint to perform an unsigned upload for testing purposes, though signed uploads are recommended for production. Get your [API key](https://console.cloudinary.com/app/settings/api-keys) and save your credentials in a `.env` file. Then, create an unsigned [upload preset](upload_presets#managing_upload_presets_using_the_settings_ui).
|

### Creating the uploadImage function
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=3 :sec=58 :player=cld} | Create an `uploadImage` function that uploads the file to Cloudinary using the provided API endpoint and upload preset. After uploading, store the returned URL and update the state with the response.
|

```react
  const uploadImage = async () => {
    let formData = new FormData()

    formData.append("file", selectedFile)
    formData.append("upload_preset", import.meta.env.VITE_CLOUDINARY_UPLOAD_PRESET)
    formData.append("api_key", import.meta.env.VITE_CLOUDINARY_API_KEY)

    await fetch(`https://api.cloudinary.com/v1_1/${import.meta.env.VITE_CLOUDINARY_CLOUD_NAME}/image/upload`, {
      method: "POST",
      body: formData,
    })
      .then(r => {
        return r.json()
      })
      .then(data => {
        setUploadedURL(data.url)
      })

  }
```

### Displaying the uploaded file
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=4 :sec=32 :player=cld} | After a successful upload, update the state with the public URL from the Cloudinary response and display the uploaded image in your application.
|

```react
      {uploadedURL && (
        <a target="_blank" href={uploadedURL}>
          <span className="uploaded-url">{uploadedURL}</span>
        </a>
      )}
```

### Testing drag-and-drop functionality
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=4 :sec=37 :player=cld} | Test your drag-and-drop functionality with Cloudinary integration. Drag a file into the drop zone, preview it, and then upload it to Cloudinary. Once uploaded, the file’s public URL is displayed, confirming successful integration.
|

## Keep learning

> **READING**:
>
> * Read our Upload widget [guide](upload_widget) and [reference](upload_widget_reference) to find out about another useful way to upload in React.

> * Check out some [React sample projects](react_sample_projects) that can be useful to you when creating your own app.

> * Take a look at our [React SDK](react_integration) to learn how to transform your [images](react_image_transformations) and [videos](react_video_transformations).

> * Watch more [Dev Hints videos](https://www.youtube.com/playlist?list=PL8dVGjLA2oMpaTbvoKCaRNBMQzBUIv7N8) on the [Cloudinary YouTube channel](https://www.youtube.com/cloudinary).

#### If you like this, you might also like...

  
  
  
      Crop and Resize Images in React
      Crop and resize images using React with Cloudinary 
  

  
  
  
    Crop and Resize Videos in React
    Crop and resize videos using React with Cloudinary
  

  
  
  
    Optimize Videos in React
    Optimize delivery of videos in a React app 
  

&nbsp;

&nbsp;Check out the Cloudinary Academy for free self-paced Cloudinary courses on a variety of developer or DAM topics, or register for formal instructor-led courses, either virtual or on-site.
&nbsp;
