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! π₯