Tutorial

How To Create Drag and Drop File Uploads in React with react-dropzone

Updated on March 23, 2021
author

joshtronic

How To Create Drag and Drop File Uploads in React with react-dropzone

Introduction

react-dropzone is an HTML5-compliant React component for handling the dragging and dropping of files.

HTML5 supports file uploads with <input type="file" />. react-dropzone provides you with additional functionality like customizing the dropzone, displaying a preview, and restricting file types and amounts.

Note: If you are working with Vue instead of React, consult our tutorial for vue-dropzone.

In this tutorial, you will learn about adding react-dropzone to your React projects and explore some of the functionality it provides.

Prerequisites

To complete this tutorial, you’ll need:

This tutorial was verified with Node v15.3.0, npm v7.4.0, react v17.0.1, and react-dropzone v11.2.4.

Step 1 — Setting Up the Project

Start with using create-react-app to generate a React App and then install dependecies:

  1. npx create-react-app react-dropzone-example

Change into the new project directory:

  1. cd react-dropzone-example

Install react-dropzone:

  1. npm install react-dropzone@11.2.4

At this point, you have a new React project with react-dropzone.

Step 2 — Adding the Dropzone Component

react-dropzone has default settings that allow you to add it with minimal configuration.

At a minimum, you will need an onDrop property that will handle the dropped files and some call-to-action text to help limit any user confusion:

src/DropzoneComponent.js
import React, { useCallback } from 'react';
import { useDropzone } from 'react-dropzone';

function DropzoneComponent() {
  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles);
  }, []);

  const {
    getRootProps,
    getInputProps
  } = useDropzone({
    onDrop
  });

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      <div>Drag and drop your images here.</div>
    </div>
  )
}

export default DropzoneComponent;

This code provides drag and drop functionality for your application.

Note: It is worth noting that even though react-dropzone is designed to drag and drop files, it does accept click events to the dropzone by default which will launch a dialog for file selection.

Add the component to your React application:

src/App.js
import DropzoneComponent from './DropzoneComponent';

function App() {
  return (
    <div className="App">
      <DropzoneComponent />
    </div>
  );
}

export default App;

Run your application and observe it in a web browser. You should see a div with the text: Drag and drop your images here.

Experiment with dragging and dropping various files to the React Dropzone component. The code currently uses a console.log to display the files. The information from uploaded files includes name, lastModified, size, and type.

At this point, you have a working React Dropzone component with the default configuration. The react-dropzone documentation additional configuration options.

Step 3 — Styling the Dropzone Component

By default, the react-dropzone will have no styles. The documentation provides styles for a common appearance that uses a combination of flexbox and dashed borders to indicate to users an area to drag and drop files.

react-dropzone also supports props for when the component is actively interacted with (isDragActive), accepted the file (isDragAccept), or rejected the file (isDragReject).

Revisit your DropzoneComponent and modify it to use isDragActive, isDragAccept, and isDragReject when applied to JPEG and PNG image file types:

src/DropzoneComponent.js
import React, { useCallback, useMemo } from 'react';
import { useDropzone } from 'react-dropzone';

const baseStyle = {
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  padding: '20px',
  borderWidth: 2,
  borderRadius: 2,
  borderColor: '#eeeeee',
  borderStyle: 'dashed',
  backgroundColor: '#fafafa',
  color: '#bdbdbd',
  transition: 'border .3s ease-in-out'
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};

function DropzoneComponent(props) {
  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles);
  }, []);

  const {
    getRootProps,
    getInputProps,
    isDragActive,
    isDragAccept,
    isDragReject
  } = useDropzone({
    onDrop,
    accept: 'image/jpeg, image/png'
  });

  const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragReject,
    isDragAccept
  ]);

  return (
    <div {...getRootProps({style})}>
      <input {...getInputProps()} />
      <div>Drag and drop your images here.</div>
    </div>
  )
}

export default DropzoneComponent;

This code will produce the following result:

Screenshot of React Dropzone with custom styles

Changing the appearance of the component for acceptions and rejections can help provide feedback to the user on whether or not their file is valid.

Step 4 — Adding Image Previews

A preview is a copy of the image that is dragged and dropped in the component. This is helpful to provide visual feedback to the user to verify the contents of the image file they selected.

Previews were removed in version 7.0.0, however, the documentation provides an alternative for readding it with a combination of Object.assign() and URL.createObjectURL().

Revisit your DropzoneComponent and modify it to use preview:

src/DropzoneComponent.js
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDropzone } from 'react-dropzone';

const baseStyle = {
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  padding: '20px',
  borderWidth: 2,
  borderRadius: 2,
  borderColor: '#eeeeee',
  borderStyle: 'dashed',
  backgroundColor: '#fafafa',
  color: '#bdbdbd',
  transition: 'border .3s ease-in-out'
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};

function DropzoneComponent(props) {
  const [files, setFiles] = useState([]);

  const onDrop = useCallback(acceptedFiles => {
    setFiles(acceptedFiles.map(file => Object.assign(file, {
      preview: URL.createObjectURL(file)
    })));
  }, []);

  const {
    getRootProps,
    getInputProps,
    isDragActive,
    isDragAccept,
    isDragReject
  } = useDropzone({
    onDrop,
    accept: 'image/jpeg, image/png'
  });

  const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragReject,
    isDragAccept
  ]);

  const thumbs = files.map(file => (
    <div key={file.name}>
      <img
        src={file.preview}
        alt={file.name}
      />
    </div>
  ));

  // clean up
  useEffect(() => () => {
    files.forEach(file => URL.revokeObjectURL(file.preview));
  }, [files]);

  return (
    <section>
      <div {...getRootProps({style})}>
        <input {...getInputProps()} />
        <div>Drag and drop your images here.</div>
      </div>
      <aside>
        {thumbs}
      </aside>
    </section>
  )
}

export default DropzoneComponent;

Note: To avoid memory leaks, you will need to call URL.revokeObjectURL(file.preview) to avoid storing the preview unnecessarily.

Now whenever a file (or files) has been dropped, the file will be appended to the state and a preview will be displayed.

Conclusion

In this tutorial, you were introduced to react-dropzone and how it could be used in a React application to provide advanced drag and drop functionality to file uploads.

If you’d like to learn more about React, take a look at our How To Code in React.js series, or check out our React topic page for exercises and programming projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
joshtronic

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.