File dropzone

A generous target for dropping one or more files.

fieldfiles
Preview
File dropzone preview
  • logo.svg13 KBUploaded
  • hero.png393 KBFailed: Too large

When to use

  • Attachments and uploads with drag and drop plus a file picker.
  • Uploads that need per-file progress, retry, and cancel through onUpload.

When not to use

  • 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.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-dropzone",
  "type": "registry:ui",
  "title": "File dropzone",
  "description": "A generous target for dropping one or more files.",
  "categories": [
    "inputs"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/file-dropzone/file-dropzone.tsx",
      "type": "registry:component",
      "target": "@components/manicat/file-dropzone/file-dropzone.tsx"
    },
    {
      "path": "registry/components/file-dropzone/file-dropzone.module.css",
      "type": "registry:component",
      "target": "@components/manicat/file-dropzone/file-dropzone.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/file-dropzone",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/file-dropzone",
    "markdown": "https://uiarc.dev/components/file-dropzone/markdown",
    "tags": [
      "field",
      "files"
    ]
  }
}

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 { FileDropzone } from "@/components/manicat/file-dropzone/file-dropzone";
import type { FileDropzoneItem } from "@/components/manicat/file-dropzone/file-dropzone";

const preloadedFiles: FileDropzoneItem[] = [
  { id: "f1", name: "logo.svg", size: 12_853, status: "uploaded" },
  { id: "f2", name: "hero.png", size: 402_134, status: "failed", error: "Too large", retryable: true },
];

export function FileDropzoneExample() {
  return (
    <FileDropzone
      label="Add files"
      description="The cover art and its variants live here."
      maxSize={5 * 1024 * 1024}
      defaultItems={preloadedFiles}
      listPlacement="below"
      note="SVG, PNG or JPG, up to 5 MB."
    />
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Asset uploader Drop files, see each one's status, and retry the ones that failed.

Asset uploader Drop files, see each one's status, and retry the ones that failed. preview
  • logo.svg13 KBUploaded
  • hero.png393 KBFailed: Too large

Keyboard interactions

KeysAction
Enter / SpaceOn the drop target, opens the native file picker.
ArrowUp / ArrowDownIn the file list, moves focus to the same action (remove or retry) on the adjacent row.
Delete / BackspaceIn the file list, removes the focused row.
⌘ + V / Ctrl + VPastes files from the clipboard, such as a screenshot, while the pointer is over the dropzone or focus is inside it. Ignored inside text fields.

Accessibility

  • 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.

Motion

  • 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.

Responsive behavior

  • 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.

Performance

  • 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

  • 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.