Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

45 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

react-mediadrop banner

npm CI License: MIT bundle size Contributor Covenant skills.sh Discord

Website Β· GitHub Β· Discord

Introduction

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.

Why

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.

Comparison

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.

Install

pnpm add react-mediadrop
# or: npm install react-mediadrop
# or: yarn add react-mediadrop

Using 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-mediadrop

Also 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/document access at render time β€” safe to import in SSR frameworks (Next.js, Remix, etc.); browser APIs only run inside event handlers, on the client.

Quickstart

React

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>
	);
}

Upload (opt-in)

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.

Blocks (shadcn registry)

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/dropzone

Swap dropzone for avatar-uploader, multi-file-upload-form, or s3-direct-upload. (Shorter @mediadrop/dropzone form pending shadcn Registry Directory review.)

What's implemented

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.

Packages

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

Example

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 dev

Open the demo, drop a file, hit "Upload all" β€” bytes land in examples/test-server/uploads/ (git-ignored).

Commands

pnpm install
pnpm build
pnpm test
pnpm typecheck
pnpm lint
pnpm size    # checks each published/bundled package's gzipped dist against its size budget

Support

Questions or issues not covered by the docs? Join the Discord, open a GitHub issue, or email oss@autorender.io.

Contributing

See CONTRIBUTING.md before opening a PR.

License

Brought to you by Autorender, MIT

About

πŸ“€ A hooks-first, headless file uploader for React

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

16 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages