Skip to main content
react-mediadrop tracks every file you add as a MediaDropFile object, backed by a small internal store you never call directly. The engine that owns this store is bundled inside react-mediadrop — it isn’t published or imported separately.

What does a file look like?

Every file you add becomes a MediaDropFile:
A file’s status is decided once, when it’s added — there’s no re-validation pass later, and uploading never changes it. status (validation) and uploadStatus (upload lifecycle) are deliberately separate fields: getAcceptedFiles()/getRejectedFiles() and maxFiles counting are all based on status alone and are completely unaffected by whether a file has started, finished, or failed uploading. See Upload.

How does the store work?

The engine backing useMediaDrop returns an object backed by a small store:
react-mediadrop wraps this with useSyncExternalStore internally — you don’t call subscribe yourself in React, you just read the hook’s return value.

How do I know when a file is being dragged?

isDragAccept/isDragReject are evaluated from DataTransferItem.type during dragenter.
Browsers don’t expose the file name while dragging — only after drop. So an accept restriction like [".png"] (an extension) can’t be evaluated mid-drag, and both flags stay false in that case. MIME-based restrictions ("image/png", "image/*") work during drag, since the MIME type is available on DataTransferItem. Use MIME types in accept if you want an accurate drag-time preview.
A custom validator also participates in this preview, but only as far as the browser lets it: some browsers hand back a real (if empty/unreadable) File from DataTransferItem.getAsFile() mid-drag, and when that happens the validator runs against it. When the browser doesn’t expose that, the validator is silently skipped for the preview — it still runs for real at drop time either way. Don’t assume the validator ran during drag; treat it as a bonus, not a guarantee. isDragActive/isDragAccept/isDragReject are per-dropzone — there’s no page-wide equivalent by default. useMediaDrop additionally returns isDragGlobal: true while a file drag is anywhere on the document, tracked via its own dragenter/dragleave/dragend/drop listeners on document (cleaned up on unmount). Don’t assume an equivalent exists outside of it; wire your own document listeners if you need the same thing somewhere else.

How does maxFiles work across a batch?

Individual restrictions (accept, minSize, maxSize) are evaluated per file — one bad file never blocks the others in the same batch. maxFiles is different: it’s evaluated across the whole file list. When you call addFiles with a batch that would exceed the remaining slots, files fill the remaining slots in order and the overflow is rejected with too-many-files. It does not reject the entire batch.

Can I use multiple dropzones on one page?

Each useMediaDrop() call owns its own drag-enter/leave depth counter and only reacts to events that bubble to its own root element:
  • Multiple independent dropzones on one page do not interfere with each other.
  • Moving the pointer across child elements inside one dropzone does not cause isDragActive to flicker (a counter, not a boolean flip, tracks enter/leave).
  • Overlapping/nested dropzones are not specially coordinated today — a known limitation, not yet solved.

Validation

Restrictions and custom validators

Upload

The queue, concurrency, retry, and cancel