Forms
IFileUpload
A drag-and-drop file field, with a browse button and a list of what has been picked.
The model is always a File[], even without multiple — in that case an array holding at most one file, and picking again replaces it.
Multiple files
Image files get a thumbnail and everything else a placeholder of the same size. The object URLs behind the thumbnails are revoked when a file leaves the list or the component unmounts.
Accepted types and sizes
accept uses the native syntax — image/*, .pdf, image/png — and is enforced on dragged-in files as well as on the browse dialog.
Put the accepted types in hint: label is the instruction, hint is the fine print.
Capping the count
Rejections
Refused files raise @reject once per drop, with an array of { file, reason }, where reason is 'type', 'size' or 'count'. The messages shown on the rows come from tooLargeText, wrongTypeText and tooManyText.
Upload progress
The component doesn't upload anything, but it can show how your upload is going. statusFor returns a file's state, and the row follows it: a bar and percentage while uploading, "Uploaded" when done, the error and a retry button when it failed. Leave progress out for an indeterminate bar.
A failure is announced to screen readers once. Progress isn't, since reading out every percent would drown everything else.
Invalid and disabled
Inside an IFormField the field passes its own validity down, so invalid rarely needs setting by hand.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
multiple | boolean | — | Accept more than one file. The model is an array either way |
accept | string | — | Native syntax: image/*, .pdf, image/png |
maxSize | number | — | Largest accepted size, in bytes |
maxFiles | number | — | Cap on how many files may be held at once |
disabled | boolean | — | Zone and browse button are inert |
invalid | boolean | — | Red border; inherited from IFormField when unset |
id | string | — | Id for the input; IFormField supplies one |
label | string | 'Drag and drop a file here' | Prompt inside the zone |
hint | string | — | Fine print under the prompt |
browseLabel | string | 'Browse files' | Text on the browse button |
statusFor | (file: File) => FileUploadStatus | undefined | — | Upload state per file, shown on its row |
removeLabel | string | 'Remove' | Accessible name for a row's remove action |
doneText | string | 'Uploaded' | Shown after the size once a file is done |
retryLabel | string | 'Retry' | Accessible name for a failed row's retry button |
failedText | string | 'Upload failed' | Error shown when a status has no error |
tooLargeText | string | 'is too large' | Message for a size rejection |
wrongTypeText | string | 'is not an accepted type' | Message for a type rejection |
tooManyText | string | 'exceeds the file limit' | Message for a count rejection |
unstyled | boolean | — | Drop built-in classes |
class | string | — | Applied to the wrapper stacking the zone above the list |
ui | { root?, dropzone?, input?, icon?, label?, browse?, hint?, list?, item?, thumbnail?, placeholder?, details?, name?, meta?, remove?, error?, progress?, actions?, retry? } | — | Per-element class overrides |
Events
| Event | Payload | When |
|---|---|---|
reject | FileRejection[] | One or more files were refused, once per drop or pick |
retry | File | The retry button on a failed row was pressed |
interface FileRejection {
file: File
reason: 'type' | 'size' | 'count'
}
interface FileUploadStatus {
state: 'uploading' | 'done' | 'error'
progress?: number // 0–100
error?: string
}Model
const files = ref<File[]>([])The component never uploads anything: it hands you File objects, and posting them is yours. statusFor and @retry let it show how that's going.