Installation
Theme
Mode

Overlays & feedback

File Dropzone

Drag-and-drop upload surface with click-to-browse, type and size validation, per-file progress, and removable rows. Drop real files onto any zone, or click to pick — the demos simulate the upload so progress bars run.

$npx shadcn@latest add @orbit/file-dropzone

Overview

Live — drop files, click to browse, or add the samples
Drag & drop files here
or browse from your computer
PDF, PNG, JPG, FIG · up to 10 MB

Variants

Pick by the room the flow gives you.

Default
Large surface for a dedicated upload step.
Drag & drop files here
or browse from your computer
PDF, PNG, JPG, FIG · up to 10 MB
Compact
Inline row for forms and side panels.
Drop files or browse
PDF, PNG, JPG, FIG · up to 10 MB
Browse

File states

Every row carries its own status — the list stays honest while uploads run.

PDF
q3-report.pdf
3.2 MB
PNG
dashboard-shot.png
64%
MP4
walkthrough.mp4
Exceeds 100 MB · 248.0 MB
FIG
wireframes.fig
Unsupported type · 5.1 MB
Uploading shows a live blue progress bar; complete turns green with a check; rejected files surface the reason inline and never start uploading.

Type & size limits

accept lists the allowed extensions (empty = any type); maxMB caps each file. Rejected files render as error rows with the reason and never call onDrop.

Images only · 5 MB
Constrain accepted types and per-file size.
Drop files or browse
PNG, JPG, GIF, SVG · up to 5 MB
Browse
Any type · 100 MB
Permissive zone for general attachments.
Drop files or browse
Any type · up to 100 MB
Browse

Props

The component is controlled and owns no upload: it validates and hands you entries via onFilesChange plus the raw accepted File objects via onDrop — you upload, then drive each row's status and progress.

PropTypeDefaultDescription
variant"default" | "compact""default"Large surface for a dedicated step, or an inline row for forms and side panels.
acceptstring[]["PDF","PNG","JPG","FIG"]Accepted extensions, uppercase. Empty array accepts any type. Also constrains the native picker.
maxMBnumber10Per-file size limit in MB.
filesFileDropzoneFile[][]Rows to render: { id, name, size, status?, progress?, error? } with status "uploading" | "done" | "error".
onFilesChange(files) => voidNext full list after files were added (already validated and flagged) or removed.
onDrop(files: File[]) => voidRaw accepted native File objects for the actual upload. Rejected files are excluded.
onRemove(file) => voidA row's × was clicked (also reflected in onFilesChange).
multiplebooleantrueAllow picking several files at once.
disabledbooleanfalseBlocks drop, click, and keyboard opening.
…restHTMLAttributesForwarded to the root <div>, including ref. FileDropzoneRow, formatFileSize, and fileExt are exported too.

Usage

Do

State the constraints up front

The caption line shows accepted types and the size cap before anyone drops a file — no surprise rejections.

Don’t

Silently swallow rejected files

A file that fails validation must appear as an error row with the reason, not vanish from the drop.

Do

Keep rows removable

A wrong file, a stalled upload — the × next to every row keeps the list under the user's control.

Don’t

Rely on drag alone

Every zone is also a button: click or Enter opens the native picker, so touch and keyboard users can upload too.

Keyboard & accessibility

The zone is a focusable button (Enter/Space opens the picker) wrapping a native file input, the file list is a real list, and every remove button carries the file's name in its accessible label. Validation errors are shown inline as text, not colour alone.

TabMoves focus to the zone, then each row's Remove button
Enter / SpaceOn the zone — opens the file picker
dropDrag files anywhere onto the dashed surface
× buttonRemove — announced as “Remove ‹file›”