File count

Use maxFiles to cap how many files can be attached at once. The default is 0, which means unlimited.

<DropUpload maxFiles={3} />

The limit applies to the whole attached list, not to a single drop: if two files are already attached and maxFiles={3}, the next drop only accepts one more.

Feedback for the user

When maxFiles is set, the drop area's description line ends with the limit ("Up to 3 files"), alongside the format and size hints — so the cap is visible before anything is dropped.

Because files over the limit never join the list, a drop that is entirely turned away would otherwise look like nothing happened. To avoid that, the component shows a short-lived notice under the drop area ("You can only attach up to 3 files") whenever a selection hits the cap. It is announced to screen readers (role="status"), and after 4 seconds it fades out while collapsing its own height, so the file list underneath glides back up on the same spring the drop area and the list already use.

Both strings come from the active locale and can be replaced through translations:

<DropUpload
  maxFiles={3}
  translations={{
    maxFilesLabel: (max) => `${max} files tops`,
    maxFilesReached: (max) => `That's ${max} already — remove one first`,
  }}
/>

What happens to the extra files

Files beyond the limit are never attached — unlike size or format rejections, they don't show up in the list as rejected entries, since the whole point of maxFiles is to keep the list capped. They are reported through onFilesRejected with the reason "tooManyFiles":

<DropUpload
  maxFiles={3}
  onFilesRejected={(rejected) => {
    const overflow = rejected.filter((file) => file.reason === "tooManyFiles")
    if (overflow.length) {
      toast.error(`Only 3 files allowed — ${overflow.length} were ignored`)
    }
  }}
/>

Files rejected for other reasons (too large, wrong type, spoofed) do stay in the list flagged as rejected, so they still take up one of the available slots. Discard one to free it up again.

Single-file uploads

With maxFiles={1} the underlying <input type="file"> drops its multiple attribute, so the browser's file picker only lets the user choose one file. Dropping several files at once still works — only the first one is taken.

<DropUpload maxFiles={1} allowedFormats={["image/*"]} autoHideDropArea />

The avatar variant is the exception to all of this: it pins maxFiles to 1 and a new image replaces the one in the circle instead of being turned away.

Like every other validation here, the limit is enforced in the browser and can be bypassed. Cap the number of files on your server too.