#Upload
Choose or drop files and follow upload progress.
#Choose and validate
Images, PDF or text · up to 5 files, 5 MB each
basic.tsx
import { Space, Upload } from '@ifhover/leaf-ui';
export function UploadBasic() {
return (
<Space direction="vertical" align="stretch">
<Upload
multiple
accept="image/*,.pdf,.txt"
maxCount={5}
maxSize={5 * 1024 * 1024}
hint="Images, PDF or text · up to 5 files, 5 MB each"
/>
</Space>
);
}
#Drag, progress and cancellation
This demo simulates progress locally. Use action or customRequest to connect your upload service.
advanced.tsx
import type { UploadRequest } from '@ifhover/leaf-ui';
import { Space, Text, Upload } from '@ifhover/leaf-ui';
const demoRequest = ({ signal, onProgress }: UploadRequest) =>
new Promise<void>((resolve, reject) => {
let percent = 0;
const cleanup = () => {
clearInterval(timer);
signal.removeEventListener('abort', abort);
};
const abort = () => {
cleanup();
reject(new DOMException('Aborted', 'AbortError'));
};
const timer = setInterval(() => {
percent += 12;
onProgress(percent);
if (percent >= 100) {
cleanup();
resolve();
}
}, 180);
signal.addEventListener('abort', abort, { once: true });
if (signal.aborted) abort();
});
export function UploadDrag() {
return (
<Space direction="vertical" align="stretch">
<Text tone="muted">
This demo simulates progress locally. Use action or customRequest to connect your upload
service.
</Text>
<Upload
drag
multiple
accept="image/*"
maxCount={4}
customRequest={demoRequest}
hint="Images only · cancellation and retry supported"
/>
</Space>
);
}
#Usage notes
Without action or customRequest, files remain ready for business-managed submission. action uses XMLHttpRequest for progress: POST sends FormData, PUT sends the raw file. A JSON response may provide url and name; customRequest can return the same fields. Validation applies to chooser and drop; uploads can be cancelled, removed and retried. A custom request must observe signal. Removing files or unmounting cancels requests and releases local preview URLs. Server-side validation is still required.
#Types
import type { UploadProps, UploadFile, UploadChangeInfo, UploadRejection, UploadRequest, UploadResult, FileItem } from '@ifhover/leaf-ui';#Manual upload and picture cards
capabilities.tsx
import { Button, Space, Upload, type UploadHandle } from '@ifhover/leaf-ui';
import { useRef } from 'react';
export function Capabilities() {
const upload = useRef<UploadHandle>(null);
return (
<Space direction="vertical" align="stretch">
<Upload
ref={upload}
autoUpload={false}
concurrency={2}
multiple
accept="image/*"
listType="picture-card"
paste
customRequest={async (request) => {
await new Promise<void>((resolve, reject) => {
const timer = setTimeout(resolve, 700);
request.signal.addEventListener(
'abort',
() => {
clearTimeout(timer);
reject(request.signal.reason);
},
{ once: true },
);
});
return {};
}}
/>
<Space>
<Button onClick={() => upload.current?.upload()}>
{'Start upload'}
</Button>
<Button variant="outline" onClick={() => upload.current?.abort()}>
{'Cancel uploads'}
</Button>
</Space>
</Space>
);
}
#UploadProps API
| Property | Type | Default | Description |
|---|---|---|---|
fileList | readonly UploadFile[] | [] | Controlled / initial file list |
defaultFileList | readonly UploadFile[] | [] | Controlled / initial file list |
onChange | (files: UploadFile[], info: UploadChangeInfo) => void | — | File list and status changes |
accept | string | — | Accepted MIME types or extensions, e.g. image/*,.pdf |
multiple | boolean | false | Multiple selection / disabled / dropzone |
disabled | boolean | false | Disable interaction. |
drag | boolean | false | Multiple selection / disabled / dropzone |
maxCount | number | — | Maximum total file count |
maxSize | number | — | Maximum bytes per file |
beforeUpload | (file: File) => boolean | File | Promise<boolean | File> | — | Validate before upload; false rejects, File transforms it |
onReject | (rejections: readonly UploadRejection[]) => void | — | Type, size, count or validation rejections |
action | string | ((file: File) => string | Promise<string>) | — | Upload URL; omitted configuration selects files only |
method | 'POST' | 'PUT' | 'POST' | POST sends FormData; PUT sends the raw file |
headers | Readonly<Record<string, string>> | — | Request headers |
data | Readonly<Record<string, string | Blob>> | — | Additional POST form data |
withCredentials | boolean | false | Include credentials in cross-origin requests |
fieldName | string | 'file' | File field name for POST |
customRequest | (request: UploadRequest) => Promise<UploadResult | void> | — | Custom async upload; use signal for cancellation |
onRemove | (file: UploadFile) => boolean | void | Promise<boolean> | Promise<void> | — | Before removal; return false to keep the file |
showFileList | boolean | true | Display the file list |
hint | ReactNode | — | Hint / chooser button or dropzone title |
children | ReactNode | — | Hint / chooser button or dropzone title |
name | string | — | Field name in native FormData. |
form | string | — | ID of the associated native form. |
required | boolean | — | Require a non-empty value; compound controls validate once. |
autoUpload | boolean | true | Start after validation; use ref.upload() when false. |
concurrency | number | 3 | Maximum concurrent upload requests. |
directory | boolean | — | Choose a directory and its files, subject to browser support. |
paste | boolean | — | Accept files from the clipboard. |
listType | 'text' | 'picture' | 'picture-card' | 'text' | File list presentation. |
#UploadFile API
Extends FileItem and adds the fields below.
| Property | Type | Default | Description |
|---|---|---|---|
uid | string | Required | Required. Unique identifier |
url | string | — | Configure url. |
name | string | — | Field name in native FormData. |
size | number | — | Presentation size. |
type | string | — | Configure type. |
status | 'ready' | 'uploading' | 'done' | 'error' | 'cancelled' | — | Configure status. |
percent | number | — | Completion percentage. |
error | string | — | Configure error. |
originFile | globalThis.File | — | Configure origin file. |
response | unknown | — | Server response |
#UploadChangeInfo API
| Property | Type | Default | Description |
|---|---|---|---|
file | UploadFile | — | File that changed |
reason | 'add' | 'progress' | 'success' | 'error' | 'remove' | 'cancel' | Required | Required. Change reason |
#UploadRejection API
| Property | Type | Default | Description |
|---|---|---|---|
file | File | Required | Required. Rejected file |
reason | 'type' | 'size' | 'count' | 'validation' | Required | Required. Rejection reason |
message | string | Required | Required. User-readable explanation |
#UploadRequest API
| Property | Type | Default | Description |
|---|---|---|---|
file | File | Required | Required. File to upload |
signal | AbortSignal | Required | Required. Cancellation signal, including removal or unmount |
onProgress | (percent: number) => void | Required | Required. Report upload progress |
#UploadResult API
| Property | Type | Default | Description |
|---|---|---|---|
url | string | — | Uploaded URL / name |
name | string | — | Uploaded URL / name |
response | unknown | — | Application response |
#FileItem API
| Property | Type | Default | Description |
|---|---|---|---|
uid | string | — | Stable identifier, recommended |
url | string | — | File URL |
name | string | — | Name, inferred from URL if omitted |
size | number | — | Bytes; omitted sizes are not displayed |
type | string | — | MIME type; inferred from the extension if omitted |
status | 'ready' | 'uploading' | 'done' | 'error' | 'cancelled' | — | Optional upload status |
percent | number | — | Upload progress from 0 to 100 |
error | string | — | Error description |
originFile | File | — | Original browser File |
#UploadHandle
| Property | Type | Default | Description |
|---|---|---|---|
upload | (uid?: string) => void | — | Required. Start a specified upload or all pending files. |
abort | (uid?: string) => void | — | Required. Abort a specified upload or all uploads. |
focus | () => void | — | Required. Focus the control. |