File upload
A complete file selection flow with constraints, progress, and error feedback.
Preview
File upload preview
Live · keyboard ready
Upload a coverSVG, PNG or JPG, up to 5 MB.Browse
When to use
- Uploading files with per-file progress, retry, and remove.
- Attachments that must be validated by type and size before upload.
- Uploads that should abort when a file is removed, via the AbortSignal.
When not to use
- Use file-dropzone when you only need to pick files without upload state.
- Use import-mapper when uploaded data needs column mapping.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "file-upload",
"type": "registry:block",
"title": "File upload",
"description": "A complete file selection flow with constraints, progress, and error feedback.",
"categories": [
"blocks"
],
"dependencies": [
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/file-upload/file-upload.tsx",
"type": "registry:component",
"target": "@components/manicat/file-upload/file-upload.tsx"
},
{
"path": "registry/components/file-upload/file-upload.module.css",
"type": "registry:component",
"target": "@components/manicat/file-upload/file-upload.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/blocks/file-upload",
"meta": {
"tier": "free",
"kind": "block",
"docs": "https://manicat.viraza.net/components/blocks/file-upload",
"markdown": "https://uiarc.dev/components/blocks/file-upload/markdown"
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { FileUpload } from "@/components/manicat/file-upload/file-upload";
export function FileUploadExample() {
return <FileUpload label="Upload a cover" description="SVG, PNG or JPG, up to 5 MB." maxSize={5 * 1024 * 1024} />;
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Cover upload A single-file uploader with a size limit and a hint about accepted formats.
Cover upload
A single-file uploader with a size limit and a hint about accepted formats. preview
Live · keyboard ready
Upload a coverSVG, PNG or JPG, up to 5 MB.Browse
cover-upload-a-single-file-uploader-with-a-size-limit-and-a-hint-about-accepted-formats-.tsxtsx
"use client";
import { FileUpload } from "@/components/manicat/file-upload/file-upload";
export function FileUploadCoverExample() {
return <FileUpload label="Upload a cover" description="SVG, PNG or JPG, up to 5 MB." maxSize={5 * 1024 * 1024} />;
}
Keyboard interactions
| Keys | Action |
|---|---|
| Enter / Space | Opens the file picker from the dropzone. |
| Tab | Moves through the dropzone and each row's retry and remove buttons. |
Accessibility
- The dropzone is role=button with aria-disabled and aria-describedby for the helper text.
- An aria-live polite status line announces added, rejected, uploaded, failed, and removed files.
- Retry and remove buttons are labelled with the file name.
- After removing a file, focus moves to the neighbouring remove button or back to the dropzone.
Motion
- The dropzone label swaps to Drop to add files while dragging; rows open and close their height on a spring.
- One spring drives the progress bar and the counted percentage, the bar folds away once the file lands, and a check draws in.
- Reduced motion jumps progress and replaces height and blur swaps with fades.
Responsive behavior
- The dropzone and list fill their container; file names ellipsize on one line.
- On touch devices the dropzone opens the native file picker, since drag and drop is desktop only.
Performance
- Uploads run through your onUpload, one call per valid file; there is no concurrency limit, so queue large batches yourself.
- The file list is not virtualized; keep it to a reasonable number of files.
Notes for AI
- Use when files are uploaded with progress. Use file-dropzone when you only need to pick files without upload state.
- Wire onUpload to fetch or XHR and honour the AbortSignal; without onUpload files are only listed and validated.