Introduction
A hooks-first, headless file uploader for React
react-mediadrop is a headless, hooks-first file uploader for React with
zero runtime dependencies. It handles intake, validation, and upload
(queue, concurrency, retry, cancel) via a single useMediaDrop hook — the
same getRootProps/getInputProps shape you already know from
react-dropzone, with upload built in. Published to npm as
react-mediadrop.
You can use react-mediadrop for:
- A drag-and-drop upload zone with your own markup and styling
- Client-side file validation (type, size, count) before anything uploads
- A queue that uploads multiple files with concurrency, retry, and cancel
- Upload progress and per-file status rendered in your own UI
Comparison
react-mediadrop sits between react-dropzone and Uppy: the same headless API shape as react-dropzone, with the upload queue only Uppy otherwise offers.
| Library | Model | Scope |
|---|---|---|
| react-dropzone | Headless, hooks-first | Drag/drop and file intake only — no upload |
| Uppy | Dashboard UI + plugin ecosystem | Upload via xhr-upload/tus/aws-s3 plugins, remote-provider import via Companion |
| FilePond | Prebuilt widget | Styled, drop-in upload UI |
| react-mediadrop | Headless, hooks-first | File intake, validation, and upload (queue, concurrency, retry, cancel) via one hook — zero runtime dependencies |
Closest to react-dropzone in API shape — useMediaDrop returns the same
getRootProps/getInputProps, plus the upload queue react-dropzone
doesn’t have.
Closest to Uppy in upload scope — a pluggable transport contract instead of a plugin ecosystem — but without a dashboard, Companion, or remote-provider import; see Roadmap for what’s not included.
Headless-first
You own the markup. getRootProps/getInputProps return plain props to
spread onto whatever elements you already have — no prebuilt widget, no
dashboard, nothing to override. Style it exactly like the rest of your app.
What’s here today
Core handles file intake, drag/drop, and validation. Upload builds on top of it: a pluggable transport contract, a queue with concurrency/retry/ cancel, and a reference XHR transport.
Not yet: pause/resume, remote-provider import, OAuth, image transforms, a prebuilt widget. See Roadmap for what’s next.
Which transport should I use?
| Transport | Import | Request shape | Resumable? |
|---|---|---|---|
| XHR | react-mediadrop/xhr-upload |
One request, whole file | No |
If your files are small enough that a dropped connection losing all progress is acceptable, plain XHR covers it.