A dropzone with its file list: drag files over and the zone lifts while its dashed edge starts to march, or click to browse. Each file becomes a row with a type icon, a name that truncates in the middle so the extension stays in view, its size and a thin progress line, moving through waiting, uploading, uploaded and failed with retry and remove. Accepted types, size and count limits reject files with a clear inline message; progress comes from your own upload function or from a progress map, uploads run three at a time and removing a row aborts its upload. Pasting files is optional.
The import and the props worth knowing about, in one place.
import { FileDrop, type FileDropUpload } from "@/components/beste/component/file-drop";
// Your uploader: report progress, honor the signal, reject to mark the row as failed
const upload: FileDropUpload = async (item, { onProgress, signal }) => {
onProgress(0.5);
console.log("uploading", item.name, signal.aborted);
onProgress(1);
};
<FileDrop
upload={upload}
accept="image/*,.pdf"
maxSize={10 * 1024 * 1024} // 10 MB
maxFiles={5}
onFilesChange={(files) => console.log(files.length, "files")}
/>
// Progress you drive yourself, keyed by item id
<FileDrop
files={files}
onFilesChange={setFiles}
progress={{ [files[0].id]: 0.4 }}
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Enter / Space | Open the file browser from the focused zone |
|---|---|
| Ctrl / Cmd + V | Add pasted files when paste is on |
| Drag and drop | Add files dropped on the zone |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
files | FileDropItem[] | — | The list of files. Controlled. |
defaultFiles | FileDropItem[] | — | The list of files when uncontrolled. |
onFilesChange | (files: FileDropItem[]) => void | — | |
upload | ( item: FileDropItem, context: { onProgress: (progress: number) => void; signal: AbortSignal }, ) => Promise<void> | — | Uploads one item; report progress and honor the signal, which aborts when the row is removed. Rejecting marks the row as failed. |
progress | Record<string, number> | — | Progress by item id, 0 to 1, for uploads you drive yourself. Wins over progress from `upload`. |
accept | string | — | Accepted types, as for the native input: "image/*,.pdf". |
multiple | boolean | — | |
maxSize | number | — | Largest file in bytes. |
maxFiles | number | — | Most files in the list. |
paste | boolean | — | Take files pasted with Ctrl or Cmd + V anywhere on the page. |
disabled | boolean | — | |
title | string | — | Main line in the zone. |
description | string | — | Hint under the title. Defaults to the accepted types and the size limit. |
size | "sm" | "default" | "lg" | — | |
tone | "muted" | "outline" | "ghost" | — | |
className | string | — |