FileUpload
A file picker with a drag-and-drop zone. The browse button is the keyboard and screen reader path; dropping is a shortcut for the pointer. Files are checked against accept, size and count before they are kept.
Drag and drop files here
PNG, JPG or PDF, up to 2 MB each. Three files at most.
<Field label="Attachments" error={error}>
<FileUpload
multiple
maxFiles={3}
maxSize={2_000_000}
accept="image/*,.pdf"
description="PNG, JPG or PDF, up to 2 MB each. Three files at most."
value={files}
onValueChange={setFiles}
onReject={(rejections) => setError(describe(rejections))}
name="attachments"
/>
</Field>Import
import { FileUpload, type FileRejection } from "@meridui/react";Examples
Single file
Without multiple, a new file replaces the old one.
Drop an image
<Field label="Avatar">
<FileUpload accept="image/*" label="Drop an image" buttonLabel="Choose image" onValueChange={(files) => setFile(files[0] ?? null)} />
</Field>Disabled
Drag and drop files here
Uploads are paused.
<FileUpload disabled description="Uploads are paused." />Uploading
FileUpload only selects files. Send them from onValueChange (or on form submit — with name, the kept files are mirrored onto the real <input type="file">) and show progress with Progress.
API reference
Renders a div; other div attributes and the ref go on it.
| Prop | Type | Default | Description |
|---|---|---|---|
value / defaultValue | File[] | – | Controlled or initial files. |
onValueChange | (files: File[]) => void | – | Called with every kept file after an add or remove. |
onReject | (rejections: FileRejection[]) => void | – | Files that failed a check, with reasons: file-invalid-type, file-too-large, file-too-small, too-many-files. |
accept | string | – | As on <input type="file">: "image/*,.pdf". Also checked on drop. |
multiple | boolean | false | Keep more than one file. |
maxSize / minSize | number | – | Size limits in bytes. |
maxFiles | number | – | Most files kept when multiple. |
label | ReactNode | "Drag and drop files here" | Main line in the dropzone. |
buttonLabel | ReactNode | "Browse files" | Text of the browse button. |
description | ReactNode | – | Hint under the label; describes the button. |
showFileList | boolean | true | Render the file list with remove buttons. |
getRemoveLabel | (file: File) => string | Remove {name} | Accessible name of a remove button. |
getStatusText | (count: number) => string | "N file(s) selected" | Announced when the selection changes. |
locale | string | – | Locale for file sizes (Intl units). |
icon | ReactNode | – | Icon above the label. |
invalid / disabled / required | boolean | – | States; inside a Field they come from it. |
name | string | – | Name of the file input for native form submit. |
Styling
| Class | Element |
|---|---|
.mrd-file-upload | Root (data-dragging, data-invalid, data-disabled) |
.mrd-file-upload__dropzone | Dashed drop area |
.mrd-file-upload__icon, __label, __description, __button | Dropzone content |
.mrd-file-upload__list, __item, __name, __size, __remove | File list |
Accessibility
Drag and drop has no keyboard equivalent, so the dropzone is not focusable; the browse button inside it is. It is described by description and, inside a Field, named by the visible button text followed by the field label. Adding or removing files updates a visually hidden role="status" region ("2 files selected"). Removing a file returns focus to the browse button.
| Key | Action |
|---|---|
| Tab | Browse button, then each remove button. |
| EnterSpace | On the browse button: open the file picker. On a remove button: remove that file. |