Tutorial
Drag and Drop File Uploads in React with react-dropzone
While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.
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.
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
andstyle
- Drag is Active:
activeClassName
andactiveStyle
- Dropped Files are Accepted:
acceptClassName
andacceptStyle
- Dropped Files are Rejected:
rejectClassName
andrejectStyle
- Dropzone is Disabled:
disabledClassName
anddisabledStyle
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! 💥