mediadrop is a headless, hooks-first file uploader for React with zero
runtime dependencies. It handles intake, drag/drop, 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. No prebuilt widget β you own the
markup.
react-mediadrop ships at 4.4 KB minified + gzipped (per
Bundlephobia); the
optional xhr-upload transport is a separate subpath import, so you only
pay for it if you use it.
Documentation and examples at https://www.mediadrop.dev/docs.
We built mediadrop for Autorender's own upload widget β the entry point for every file and media asset into our pipeline. It went through several iterations before it looked like this: a lightweight, hooks-first, headless core, with a pluggable transport layer instead of one fixed upload path.
What came out of it is a set of ordinary React primitives β hooks, validation, a transport contract β the same shape whether you're wiring them into a media pipeline or a plain upload form. We're open-sourcing mediadrop so any team building an uploader can start from the same primitives we did.
If you've used react-dropzone, the API will feel familiar β
useMediaDrop returns the same getRootProps/getInputProps shape, plus a
built-in upload queue react-dropzone doesn't have.
mediadrop is pre-1.0 (0.1.1), following semver β minor version bumps may
include breaking changes until 1.0. Full history in the
changelog.
| 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 the
scope reference for what's not
included.
pnpm add react-mediadrop
# or: npm install react-mediadrop
# or: yarn add react-mediadropUsing an AI coding agent? Also install the Agent Skill so it integrates the API correctly on the first try instead of guessing from the package name:
npx skills add autorender/react-mediadropAlso indexed on Context7 β reachable via MCP from Cursor, Claude Code, Windsurf, and other Context7-compatible tools with no local install.
- Ships as ESM with TypeScript types included β works with any modern bundler.
- Peer dependency on React 18+, nothing else.
- No
window/documentaccess at render time β safe to import in SSR frameworks (Next.js, Remix, etc.); browser APIs only run inside event handlers, on the client.
import { useMediaDrop } from "react-mediadrop";
function Dropzone() {
const { getRootProps, getInputProps, files } = useMediaDrop({
restrictions: { accept: ["image/png", "image/jpeg"], maxFiles: 5 },
});
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
{files.length} file(s) selected
</div>
);
}import { useMediaDrop } from "react-mediadrop";
import { createXhrUploadTransport } from "react-mediadrop/xhr-upload";
function Uploader() {
const { files, uploadAll } = useMediaDrop({
transport: createXhrUploadTransport({ endpoint: "/api/upload" }),
concurrency: 3,
retries: 2,
});
return (
<button onClick={() => uploadAll()}>Upload {files.length} file(s)</button>
);
}Without transport, nothing is uploaded β useMediaDrop only tracks
intake/validation state. See the
quickstart
and upload guide for
the full API.
Prebuilt, copy-into-your-project blocks β dropzone, avatar uploader, multi-file upload form, S3 direct-upload β installable via the shadcn CLI's GitHub registry support, no separate registry server required:
npx shadcn@latest add autorender/react-mediadrop/dropzoneSwap dropzone for avatar-uploader, multi-file-upload-form, or
s3-direct-upload. (Shorter @mediadrop/dropzone form pending shadcn
Registry Directory review.)
Core: file intake from a picker or drag/drop, sync validation
(accept/maxFiles/minSize/maxSize + a custom validator), and drag
state (isDragActive/isDragAccept/isDragReject).
Upload (opt-in via transport): a pluggable transport contract, a queue
with concurrency limit + shared retry/backoff, cancel via AbortSignal, and
a reference react-mediadrop/xhr-upload transport.
Pause/resume, remote-provider import, OAuth, image transforms, a prebuilt widget, and any vendor-specific adapter are not implemented β see the scope reference for the full, authoritative list.
Only react-mediadrop is published to npm β packages/core and
packages/xhr-upload are internal, workspace-only source packages bundled
directly into it at build time. skills/mediadrop is a separate
integration guide, not bundled into the package. Only react-mediadrop
matters if you're a consumer β the rest is listed here for contributors.
| Package | Published? | What it is |
|---|---|---|
packages/react |
react-mediadrop |
The useMediaDrop hook + the react-mediadrop/xhr-upload subpath |
packages/core |
internal | File intake, validation, drag/drop, upload-queue/retry primitives |
packages/xhr-upload |
internal | Reference XMLHttpRequest upload transport |
skills/mediadrop |
β | Integration guide for coding agents |
examples/react-demo exercises react-mediadrop against a real backend
(examples/test-server, a plain Express app) instead of a faked dev-server
mock.
| Example | Binding | Transports covered |
|---|---|---|
react-demo |
react-mediadrop |
react-mediadrop/xhr-upload |
test-server |
β | Real Express backend for react-demo |
# terminal 1 β backend, listens on http://localhost:8787
pnpm --filter test-server dev
# terminal 2 β frontend
pnpm --filter react-demo devOpen the demo, drop a file, hit "Upload all" β bytes land in
examples/test-server/uploads/ (git-ignored).
pnpm install
pnpm build
pnpm test
pnpm typecheck
pnpm lint
pnpm size # checks each published/bundled package's gzipped dist against its size budgetQuestions or issues not covered by the docs? Join the Discord, open a GitHub issue, or email oss@autorender.io.
See CONTRIBUTING.md before opening a PR.
Brought to you by Autorender, MIT
