File dropzone

A generous target for dropping one or more files.

pnpm dlx shadcn@latest add @uiarc/file-dropzone
Live · keyboard ready
  • Attachments and uploads with drag and drop plus a file picker.
  • Uploads that need per-file progress, retry, and cancel through onUpload.
  • Use input with type file only when a native picker with no list is enough.
  • Use empty-state when the drop area is the only thing on an empty page and needs a larger call to action.

Installation

Add File dropzone with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/file-dropzone

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { FileDropzone } from "@/registry/components/file-dropzone/file-dropzone"; export function AttachmentUpload() {  return (    <FileDropzone      accept=".pdf,image/*"      maxFiles={3}      maxSize={10 * 1024 * 1024}      onUpload={async (item, { onProgress, signal }) => {        await uploadFile(item.file!, { onProgress, signal });      }}    />  );}

Folding prompt with a size limit

example.tsx
<FileDropzone  label="Add receipts"  accept="image/*,.pdf"  maxFiles={10}  maxSize={5 * 1024 * 1024}  compactAt={2}  listPlacement="inside"  onFilesChange={setFiles}/>

API reference

2 parts. The first is the root.

FileDropzone

A drop target and file picker with a file list that can run uploads with progress, retry, and removal.

PropTypeDefaultDescription
acceptstring–Accepted types, as in the native accept attribute (".pdf", "image/*"). Others are rejected with an error.
multiplebooleantrueAllow several files.
maxFilesnumber5Most files the list holds.
onFilesChange(files: File[]) => void–Called with the selected File objects whenever the list changes.
labelstring"Add files"Main prompt on the drop target.
descriptionstring"Drop files here or choose from your device"Secondary prompt.
defaultItemsFileDropzoneItem[]–Rows present at mount, such as earlier uploads. They render without an entrance.
onUpload(item: FileDropzoneItem, options: { onProgress: (percent: number) => void; signal: AbortSignal }) => Promise<void>–Uploads each added file. Report progress, resolve on success, reject with an Error whose message becomes the row's reason. Removing a row aborts the signal.
maxSizenumber–Bytes. Larger files fail with a size reason and never upload.
listPlacement"below" | "inside""below"Render the list under the target or inside its edge.
notestring–Replaces the small line under the description (defaults to accepted types or the file limit).
dropLabelstring–Label while files hover over the target.
compactAtnumber–Once the list holds this many files, the prompt folds to a slim bar.

FileDropzoneItem

One row in the list, used by defaultItems and onUpload.

PropTypeDefaultDescription
idRequiredstring–Stable id.
nameRequiredstring–File name; its extension picks the type icon.
sizeRequirednumber–Bytes.
statusFileDropzoneStatus–Upload state of the row.
progressnumber–Upload percent.
errorstring–Failure reason shown on the row.
retryableboolean–Shows a retry button when failed.
fileFile–The File, for items the visitor added.
previewstring–Thumbnail URL shown instead of the type icon. Image files added by the visitor get an object URL automatically, revoked when the row is removed or the component unmounts. Falls back to the icon if the image fails.
EnterorSpace
On the drop target, opens the native file picker.
ArrowUporArrowDown
In the file list, moves focus to the same action (remove or retry) on the adjacent row.
DeleteorBackspace
In the file list, removes the focused row.
⌘+VorCtrl+V
Pastes files from the clipboard, such as a screenshot, while the pointer is over the dropzone or focus is inside it. Ignored inside text fields.
  • The target is a native button; the hidden file input is removed from the tab order.
  • Uploading rows expose role="progressbar" with aria-valuenow; remove and retry buttons are labelled with the file name.
  • Additions, completions, and failures are announced through a polite role="status" region; rejection errors use role="alert".
  • Removing a row moves focus to a neighbouring row so keyboard users are not dropped.
  • The icon lifts while files hover, the edge animates, rows enter and collapse on a smooth spring, and progress bars ease toward their target.
  • Reduced motion replaces height and lift animations with short fades and keeps progress changes instant.
  • The file list is a container query: below 440px retry becomes icon-only, and below 300px the file icon hides.
  • File names and failure reasons ellipsize instead of wrapping.
  • The whole target is one tap area that opens the native picker, so it works without drag and drop on touch.
  • The dashed edge is refitted by a ResizeObserver, plus a rAF loop only while the corner radius is transitioning.
  • Rows are not virtualized and maxFiles defaults to 5; row entrances stagger up to eight steps.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use for file attachments and uploads. Without onUpload the list shows plain selections; read them from onFilesChange and submit yourself.
  • Files can be dropped, picked, or pasted. Pass preview on defaultItems (for example a stored thumbnail URL) to show earlier image uploads as thumbnails.
  • With onUpload, the component manages per-file status, retry, and abort; wire it to fetch or XHR and pass signal through.
  • Also exports formatFileSize(bytes) and the FileDropzoneItem, FileDropzoneStatus, and FileDropzoneUpload types.

The full library index for assistants is at /llms.txt.