Installation
Usage
"use client"
import { FileDropzone } from "@/components/file-dropzone"
export function Attachments() {
return (
<FileDropzone
accept="image/*,.pdf"
maxSize={5 * 1024 * 1024}
maxFiles={4}
upload={async (file, onProgress) => {
const body = new FormData()
body.append("file", file)
await fetch("/api/upload", { method: "POST", body })
onProgress(1)
}}
/>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| accept | string | — | Like the input's accept: "image/*,.pdf". |
| maxSize | number | — | Largest file in bytes. |
| maxFiles | number | Infinity | Most files at once. |
| upload | (file, onProgress, signal) => Promise<void> | — | Upload one file and report 0–1 progress; throw to fail it. The signal aborts on cancel. |
| onFilesChange | (files: DropzoneFile[]) => void | — | Called after the list changes. |
| title / hint | ReactNode | "Drop files here or browse" / from limits | Text inside the zone. |
| label | string | "Upload files" | Accessible name of the button and file list. |
| thumbnails | boolean | true | Show a thumbnail for images (a temporary blob: URL, freed on remove). |
| paste | boolean | true | Accept files pasted with Ctrl/⌘+V while the zone has focus. |
| --dropzone-accent | CSS variable | --primary | Drag and progress colour. |
Accessibility
- The zone is a real button that opens the native file picker (Enter / Space).
- Files can be pasted into the focused zone, not only dragged, so keyboard users have a fast path too.
- Refused files are announced with a reason; successes are announced politely.
- Each upload is a progressbar with its file name; Cancel, Remove and Retry buttons name their file.
- The marching border, fanning pages, shake on refusal and row collapse are all removed under prefers-reduced-motion.
Changelog
- v1.0.0Latest
First release.