Skip to content

Inputs

File upload

A drop zone that also opens the file dialog, plus a file list with progress bars, status and remove. Files are checked against accept and maxSize before you see them, and rejected ones come back with a reason so you can explain what went wrong.

On this page
  • fernhill-brand-guide.pdfUploaded
    2.4 MB
  • invoice-FHS-0142.pdf64%

Usage

components/ui/file-upload.tsx
import { FileUpload } from "@/components/ui/file-upload"; export function Example() {  return <FileUpload accept="image/*,.pdf" maxSize={10 * 1024 * 1024} onFiles={(files) => upload(files)} />;}

Examples

Upload with progress

Drop files or click to browse. Progress is simulated in the browser; swap the interval for your upload request's progress events.

  • fernhill-brand-guide.pdfUploaded
    2.4 MB
  • invoice-FHS-0142.pdf64%

File list states

  • studio-photos.zip38%
  • contract-signed.pdfUploaded
    598 KB
  • logo-final.pngUploaded
    1.3 MB
  • timesheet-october.xlsx
    Spreadsheets aren't supported

Compact

A single-row zone for forms and side panels.

Disabled

Props

FileUpload

  • onFiles(files: File[]) => voiddefault: —Accepted files from a drop or the dialog.
  • onReject(rejections: { file, reason }[]) => voiddefault: —Files that fail accept ("type") or maxSize ("size").
  • acceptstringdefault: —Same syntax as the input attribute, e.g. "image/*,.pdf".
  • maxSizenumberdefault: —Max bytes per file.
  • multiplebooleandefault: trueAllow more than one file.
  • title / hintReactNodedefault: —Main line and the line under it.
  • variant"default" | "compact"default: "default"Tall zone or single row.
  • disabledbooleandefault: —Ignore drops and clicks.
  • namestringdefault: —Name of the underlying file input for native forms.

FileItem

  • namerequiredstringdefault: —File name, truncated when long.
  • sizerequirednumberdefault: —Size in bytes, shown formatted.
  • typestringdefault: —MIME type; images get an image icon.
  • status"uploading" | "done" | "error"default: "done"Row state.
  • progressnumberdefault: 00–100 while uploading.
  • errorReactNodedefault: —Reason shown when status is error.
  • onRemove / onRetry() => voiddefault: —Show remove (cancel while uploading) and retry buttons.

Accessibility

  • The zone is a <label> wrapping a visually hidden <input type="file">: Tab focuses it, Enter or Space opens the file dialog, and the focus ring wraps the whole zone.
  • Dragging is a pointer-only shortcut; everything it does is also possible through the dialog.
  • Each upload has a role="progressbar" named after the file, with aria-valuenow.
  • Remove, cancel and retry buttons are labelled with the file name (“Remove logo-final.png”).
  • Status never relies on color alone: finished files get a check icon announced as “Uploaded”, failed ones show the reason in text.

Suggested