Drag and Drop File Uploads in React with react-dropzone

joshtronic

Still using <input type="file" /> to handle file uploads in your React app? What if I told you there was a better way? react-dropzone is a simple (and HTML5-compliant) React.js component for handling the dragging and dropping of files.

If you're working with Vue instead of React, have a look at vue-dropzone.

Installation

Before we can use react-dropzone, we need to add it to our project. The follow code also depends on superagent to demonstrate uploading files to a server.

We can easily add both via npm:

$ npm install --save react-dropzone superagent

Or via yarn:

$ yarn add react-dropzone superagent

After installation you can import react-dropzone as you would any other React component:

import ReactDropzone from 'react-dropzone';

Basic Usage

Even though react-dropzone comes with a ton of available options, its sane defaults allow you to get pretty far out of the box.

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:

import React, { Component } from "react";
import { render } from "react-dom";

import ReactDropzone from "react-dropzone";
import request from "superagent";

class App extends Component {
  onDrop = (files) => {
    // POST to a test endpoint for demo purposes
    const req = request.post('https://httpbin.org/post');

    files.forEach(file => {
      req.attach(file.name, file);
    });

    req.end();
  }

  render() {
    return (
      <div className="app">
        <ReactDropzone
          onDrop={this.onDrop}
        >
          Drop your best gator GIFs here!!
        </ReactDropzone>
      </div>
    );
  }
}

const container = document.createElement("div");
document.body.appendChild(container);
render(<App />, container);

Upon dropping files on the dropzone, the onDrop event will fire, receiving an array of File objects which are POSTed to a test endpoint which will always be successful.

Ready to handle file uploads on your backend server? Check out our guide on Uploading Images to a Node.js Backend Using Multer and Express 🐊 🐊 🐊

It's 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.

More Options

Even though we can get away without much in the way of configuration, react-dropzone does include some pretty exhaustive configuration options.

You can do things like limit the accepted file types, set minimum and maximum allowed sizes, disable dropping multiple files and much more!

Fortunately, this project is well documented and a full list of properties is available here.

Styling

Some of the more notable properties for react-dropzone are the styling options available. By default the dropzone presents itself as a 200px by 200px square with rounded corners and a dashed border.

The component itself has five distinct states that can be styled as you see fit. Styling can be done via class names or by passing in style objects.

Each state has it’s own set of class name and style properties:

  • Default State: className and style
  • Drag is Active: activeClassName and activeStyle
  • Dropped Files are Accepted: acceptClassName and acceptStyle
  • Dropped Files are Rejected: rejectClassName and rejectStyle
  • Dropzone is Disabled: disabledClassName and disabledStyle

Keep in mind that setting any of the aforementioned properties will overwrite the default style. If you would like to extend the existing style, you will want to start with these CSS properties:

position: relative;
width: 200px;
height: 200px;
border-width: 2px;
border-color: rgb(102, 102, 102);
border-style: dashed;
border-radius: 5px;

Image Previews

Another cool configuration option that is enabled by default is the generation of a preview. This is especially useful when working with images as you can display a preview to the user before an upload has even started:

import React, { Component, Fragment } from "react";
import { render } from "react-dom";

import ReactDropzone from "react-dropzone";

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      files: [],
    };
  }

  onPreviewDrop = (files) => {
    this.setState({
      files: this.state.files.concat(files),
     });
  }

  render() {
    const previewStyle = {
      display: 'inline',
      width: 100,
      height: 100,
    };

    return (
      <div className="app">
        <ReactDropzone
          accept="image/*"
          onDrop={this.onPreviewDrop}
        >
          Drop an image, get a preview!
        </ReactDropzone>
        {this.state.files.length > 0 &&
          <Fragment>
            <h3>Previews</h3>
            {this.state.files.map((file) => (
              <img
                alt="Preview"
                key={file.preview}
                src={file.preview}
                style={previewStyle}
              />
            ))}
          </Fragment>
        }
      </div>
    );
  }
}

const container = document.createElement("div");
document.body.appendChild(container);
render(<App />, container);

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

From the react-dropzone maintainer: react-dropzone doesn't manage dropped files. You need to destroy the object URL yourself whenever you don't need the preview by calling window.URL.revokeObjectURL(file.preview); to avoid memory leaks.


I hope this article has been a helpful introduction to react-dropzone.

You can find a working demo of the code samples in this article out on CodeSandbox.

Enjoy! πŸ’₯

  Tweet It

πŸ•΅ Search Results

πŸ”Ž Searching...