FileDummy Logo
FileDummy
File Upload & Handling

Drag and Drop File Upload in React with react-dropzone

Build a polished drag-and-drop file upload component in React using react-dropzone. Covers MIME filtering, file previews, and upload progress with working code.

October 29, 20269 min read1,420 views
reactreact-dropzonedrag-dropfile-uploadfrontend

Building a smooth drag-and-drop file upload interface in React enhances usability and engagement. In this guide, we build an accessible, responsive dropzone component using react-dropzone with full file preview support and upload progress.

Installing react-dropzone

Terminal
npm install react-dropzone lucide-react
Verified Test Asset.pdf

Download a standard 10MB test PDF to test your React drag-and-drop dropzone component.

Download 10MB PDF Sample →

Complete React Component

TSX
import React, { useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { UploadCloud, FileText, CheckCircle2, AlertCircle } from 'lucide-react';

export function FileDropzone() {
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  const onDrop = useCallback((acceptedFiles: File[], fileRejections: any[]) => {
    setErrorMessage(null);

    if (fileRejections.length > 0) {
      const error = fileRejections[0].errors[0];
      setErrorMessage(error.message);
      return;
    }

    if (acceptedFiles.length > 0) {
      setSelectedFile(acceptedFiles[0]);
    }
  }, []);

  const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
    onDrop,
    maxFiles: 1,
    maxSize: 20 * 1024 * 1024, // 20MB
    accept: {
      'application/pdf': ['.pdf'],
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
      'image/*': ['.png', '.jpg', '.jpeg'],
    },
  });

  return (
    <div className="max-w-xl mx-auto my-8">
      <div
        {...getRootProps()}
        className={`p-8 border-2 border-dashed rounded-2xl text-center cursor-pointer transition-colors ${
          isDragActive
            ? 'border-blue-500 bg-blue-500/10'
            : isDragReject
            ? 'border-red-500 bg-red-500/10'
            : 'border-slate-700 bg-slate-900/50 hover:border-slate-600'
        }`}
      >
        <input {...getInputProps()} />
        <div className="flex flex-col items-center justify-center space-y-3">
          <div className="p-3 bg-blue-500/10 rounded-xl text-blue-400">
            <UploadCloud className="w-8 h-8" />
          </div>
          {isDragActive ? (
            <p className="text-sm font-medium text-blue-400">Drop the file here...</p>
          ) : (
            <div>
              <p className="text-sm font-semibold text-white">
                Click to upload or drag and drop
              </p>
              <p className="text-xs text-slate-400 mt-1">
                PDF, DOCX, PNG, or JPG (max 20MB)
              </p>
            </div>
          )}
        </div>
      </div>

      {selectedFile && (
        <div className="mt-4 p-4 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-between">
          <div className="flex items-center space-x-3">
            <FileText className="w-5 h-5 text-blue-400" />
            <div>
              <p className="text-sm font-medium text-white">{selectedFile.name}</p>
              <p className="text-xs text-slate-400">
                {(selectedFile.size / (1024 * 1024)).toFixed(2)} MB
              </p>
            </div>
          </div>
          <CheckCircle2 className="w-5 h-5 text-emerald-400" />
        </div>
      )}

      {errorMessage && (
        <div className="mt-4 p-3 rounded-lg bg-red-500/10 border border-red-500/20 text-red-400 text-xs flex items-center space-x-2">
          <AlertCircle className="w-4 h-4 flex-shrink-0" />
          <span>{errorMessage}</span>
        </div>
      )}
    </div>
  );
}

Dropzone UX Best Practices

  • Visual feedback on drag over: Dim background or illuminate borders when a valid file is hovering.
  • Clear rejection states: Show distinct red styling if an unsupported file format is dragged over.
  • Keyboard navigation: Ensure users who rely on keyboards can press Tab to focus the dropzone and Enter to open the native OS file picker.
NDL

Nguyen Dai Long

Author

Backend Lead • Distributed Systems & Cloud Edge Architecture Specialist

4+ years designing high-throughput file ingestion pipelines, database architectures, and distributed edge storage on Cloudflare R2 & AWS S3. Founder of FileDummy and the NDL Ecosystem.

Was this article helpful?

Click Like to support the author and help other developers discover this guide.

Engineering Discussion & Feedback (0)

Share benchmark results, report edge cases, or ask technical questions.

0/3000

No comments yet. Be the first developer to start the discussion!

Frequently Asked Questions

What is the difference between react-dropzone and the HTML5 drag-and-drop API?â–¾

react-dropzone wraps the HTML5 File API with an onDrop callback, MIME type filtering via the accept prop, maxSize validation, and accessible keyboard support — saving 100+ lines of boilerplate compared to raw HTML5 drag events.

How do I limit file types in react-dropzone?â–¾

Pass the accept prop as an object: { 'application/pdf': ['.pdf'], 'image/*': ['.jpg', '.png'] }. This is the react-dropzone v12+ API (breaking change from the old string format in v11).

Can react-dropzone upload files directly to S3?â–¾

react-dropzone only provides the File object — it does not handle uploads. Combine it with a presigned S3 PUT request or the tus-js-client library to upload directly from the browser to S3/R2 without a proxy server.

Related Articles