File upload
Drop zone with type and size validation, progress and removal. Files stay in the browser.
Playground
Drop real files or use the sample batch. Validation, progress, failure and retry all run locally: only the name, size and type are read, and nothing is uploaded.
Files stay in your browser. Nothing is sent to a server.
Props
1import { FileUpload } from "@/components/ui/file-upload"23<FileUpload4 accept="image/png,image/jpeg,application/pdf"5 maxSize={5 * 1024 * 1024}6 onUpload={(file, { onProgress, signal }) => uploadToStorage(file, { onProgress, signal })}7/>States
The drop target at rest, hovered, focused and disabled, then a file row while uploading, after a rejection and when complete.
- Default
rest - Hover
:hover - Focus
:focus-visible acme-msa-2026.pdf
48%885 KB of 1.8 MB
Loadingrole=progressbar- Disabled
disabled floorplan-scan.jpg
Not added7.2 MB
This file is 7.2 MB; the limit is 5 MB. Compress it or export at a lower resolution.
Errordata-status=rejectedacme-msa-2026.pdf
Uploaded1.8 MB
Successdata-status=complete
Examples
The sample batch walks every path: two clean uploads, a dropped connection you can retry, a file of the wrong type and one over the size limit.
Acme Corporation renewal
Contracts and invoices for the 2026 renewal
Files stay in your browser. Nothing is sent to a server.
Profile photo
PNG or JPG up to 5 MB. Drop an image on the circle or choose one.
Files stay in your browser. Nothing is sent to a server.
Keyboard
- Focus the drop zone, then each file's actions
- Tab
- Open the file dialog
- EnterorSpace
- Cancel, retry or remove the focused file
- Enter
Semantics and ARIA
- The drop zone is a real
<button>that opens a hidden<input type="file">, so drag and drop is never the only way in. - Each upload renders
role="progressbar"witharia-valuenowand a label naming the file. - A polite
role="status"region announces transitions (uploading, uploaded, failed) instead of every percent. - Errors are text next to the file and linked with
aria-describedby, and say how to fix the problem, not just what went wrong. - Icon buttons carry the file name in their label, for example
Retry globex-invoice-0923.pdf. - Files are never read or sent: validation uses
name,sizeandtypeonly.