Simple HTML5 drag-drop zone with React.js
react-dropzone is a hook-based React library that implements HTML5-compliant file drag-and-drop zones. With over 7 million weekly downloads, it provides a thin abstraction over the native File API, returning props and callbacks that you spread onto your components to enable file selection via drag-drop or click interactions.
The library solves a common problem in React applications: native file inputs are notoriously difficult to style and lack built-in drag-and-drop support. react-dropzone handles the complexity of managing drag events, file validation, and accessibility while giving you complete control over styling and behavior. The entire package weighs around 10KB with no external dependencies beyond React itself.
At its core, the useDropzone() hook returns three main items: getRootProps() for the drop zone container, getInputProps() for the hidden file input, and state values like isDragActive. This pattern integrates naturally with functional React components and works seamlessly with TypeScript. The library is maintained actively and has proven stable across React versions 16 through 18.
Developers choose react-dropzone when they need file upload functionality without the overhead of full-featured upload libraries. It intentionally omits features like progress bars, thumbnails, and server communication—you integrate those yourself using the accepted files array and your preferred upload strategy.
import React, { useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
function FileUploader() {
const [files, setFiles] = useState([]);
const [errors, setErrors] = useState([]);
const onDrop = useCallback((acceptedFiles, rejectedFiles) => {
setFiles(prev => [
...prev,
...acceptedFiles.map(file => ({
file,
preview: URL.createObjectURL(file),
id: Math.random().toString(36)
}))
]);
if (rejectedFiles.length > 0) {
setErrors(rejectedFiles.map(({ file, errors }) => ({
name: file.name,
message: errors.map(e => e.message).join(', ')
})));
}
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
'image/jpeg': [],
'image/png': [],
'image/webp': []
},
maxSize: 5 * 1024 * 1024,
maxFiles: 10
});
const removeFile = (id) => {
setFiles(prev => {
const file = prev.find(f => f.id === id);
if (file) URL.revokeObjectURL(file.preview);
return prev.filter(f => f.id !== id);
});
};
React.useEffect(() => {
return () => files.forEach(f => URL.revokeObjectURL(f.preview));
}, [files]);
return (
<div>
<div
{...getRootProps()}
style={{
border: '2px dashed #ccc',
padding: '40px',
textAlign: 'center',
backgroundColor: isDragActive ? '#e0e0e0' : '#fafafa',
cursor: 'pointer'
}}
>
<input {...getInputProps()} />
<p>{isDragActive ? 'Drop files here' : 'Drag images or click to select (max 5MB)'}</p>
</div>
{errors.length > 0 && (
<div style={{ color: 'red', marginTop: '10px' }}>
{errors.map((err, i) => (
<div key={i}>{err.name}: {err.message}</div>
))}
</div>
)}
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', marginTop: '20px' }}>
{files.map(({ id, file, preview }) => (
<div key={id} style={{ position: 'relative' }}>
<img src={preview} alt={file.name} style={{ width: '100px', height: '100px', objectFit: 'cover' }} />
<button
onClick={() => removeFile(id)}
style={{ position: 'absolute', top: 0, right: 0, background: 'red', color: 'white', border: 'none' }}
>
×
</button>
</div>
))}
</div>
</div>
);
}
export default FileUploader;Image upload with preview: Build a profile picture uploader that accepts only images, validates file size, and displays thumbnails before upload. Use acceptedFiles from onDrop to create object URLs with URL.createObjectURL() for instant previews.
Document management systems: Create a multi-file document intake form that accepts PDFs and Word docs, validates against a 10MB limit, and adds files to a queue. Combine with a state management solution to track upload progress per file.
CSV data import: Implement a data import wizard where users drag CSV files, validate the MIME type is text/csv, and parse contents client-side before submission. The library handles file validation while your parser processes the data.
Batch image processing: Build a graphic design tool where users drop multiple images, restrict to PNG/JPEG formats, and process them in a canvas element. The maxFiles option can limit uploads while accept ensures correct formats.
Form attachments: Add file upload capability to a contact form or support ticket system, allowing multiple attachments with size restrictions. Use the rejectedFiles array to display specific validation errors to users.
npm install react-dropzonepnpm add react-dropzonebun add react-dropzone