ComponentsForms & inputs

File upload

Pick or drop files, watch them upload with progress, retry failures, remove or cancel. The drop target is a real button, so the keyboard path is the same as the pointer path; type, size and count rejections come back as localized messages. Without an upload handler the files simply go with the form.

Native file input · Drag and Drop API components/file-upload.tsx, components/progress.tsx, format/core.tstheme · material · accent · density · font

ID copy, signed contract and diploma. Name a file “fail.pdf” to see an error.

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { Field, FileUpload } from "@vamos-ui/react";

<Field label="Documents">
  <FileUpload
    accept=".pdf,image/*"
    maxSize={10_000_000}
    maxFiles={6}
    upload={async (file, { signal, onProgress }) => {
      const { id, url } = await uploadToStorage(file, { signal, onProgress });
      return { id, url };
    }}
  />
</Field>

File names are NFC-normalised: macOS sends decomposed characters, which breaks the display of ş, ğ and é.

Resumable / chunked uploads (tus) are out of scope — wire them inside your upload function.

Examples

Button variant

FileUploadButton — for toolbars and tight forms. Dropping on the button still works.

Quote attachments

PDF, DOCX, or XLSX · up to 20 MB

Image upload

One image with a live preview in a fixed aspect ratio; Replace and Remove appear on hover or keyboard focus (always on touch).

1600 × 900 or larger.

Restrictions

accept, maxSize and maxFiles reject with a reason and a localized message; sizes use the locale (2,4 MB in Turkish).

Drop a PDF, a 3 MB photo or more than three files to see each rejection.

Existing files (compact)

Server files are UploadFile objects without file. The compact variant sits in a form row like an input.

Master services agreement — Moda Wellness.pdf, Rate card 2026.xlsx
  • Master services agreement — Moda Wellness.pdf1.8 MBUploaded
  • Rate card 2026.xlsx96.4 kBUploaded

2 files · 0 new

Plain form submit

No upload: the hidden file input carries the files, so FormData and Server Actions work as is.

Sent with the form — no upload handler needed.

API

FileUpload

PropTypeDefault
accept
MIME types, type/* wildcards and extensions: "image/*,.pdf".
string | string[]—
maxSize / minSize
Bytes per file.
number—
maxFiles
Counted over the list (failed files don't count). maxFiles={1} replaces the file.
number—
multiple
Allow several files per pick.
booleantrue unless maxFiles is 1
value / defaultValue / onValueChange
{ key, file?, name, size, type, status, progress?, error?, remoteId?, url?, previewUrl? }.
UploadFile[]—
upload
Uploads each file when added; cancel aborts the signal; a rejected promise shows its message with Retry.
(file, { signal, onProgress }) => Promise<{ id, url? }>—
concurrency
Parallel uploads.
number3
onReject
reason: type | size | small | count.
(rejections: { file, reason, message }[]) => void—
variant
Look of the trigger.
"dropzone" | "button" | "compact""dropzone"
hint
Replaces the generated hint ("PDF or PNG · up to 10 MB").
ReactNode—
showList
Render the file list (or render your own with FileUploadList/Item).
booleantrue
name · required · disabled · invalid
Form name for the native input (only without upload); Field wiring.
——
labels
Built-in strings (upload namespace).
Partial<FileUploadLabels>—

ImageUpload

PropTypeDefault
value / defaultValue / onValueChange
The single image.
UploadFile | null—
aspect
CSS aspect ratio of the frame.
string"16/9"
fit
contain for logos.
"cover" | "contain""cover"
accept / maxSize / upload / onReject / hint
As FileUpload.
——

FileUploadList · FileUploadItem

PropTypeDefault
file
Thumbnail or type icon, name, size, status, per-file progressbar.
UploadFile—
onRemove / onRetry
Remove (or cancel while uploading) and retry buttons, named after the file.
() => void—

useFileDropzone

PropTypeDefault
useFileDropzone(options)
The drag-and-drop + picker wiring with localized rejections, for custom drop targets.
{ rootProps, inputProps, open, dragging, hint }—