Forms
Upload
A file queue with a trigger, a list, per-file progress and retry — plus `Upload.Dragger`, the drop-target form. The queue arithmetic is framework-free and lives in `@crosskit-ui/core`, so the `accept` filter applies to a drop as well as to the file dialog; the attribute alone only filters the OS dialog.
data-scope="upload"
What you get for free
- Upload.Dragger, with a drag counter that does not flicker over child elements
- Progress as an inline custom property, so the bar grows from the inline start in RTL too
- Retry on a failed file, which is the same transition as a first attempt
- A request that resolves after its file was removed cannot put the row back
- customRequest, for a transport that is not a plain multipart POST
Usage
import { Upload, Button } from "@crosskit-ui/react";
<Upload action="/api/upload" multiple accept="image/*" maxCount={5}>
<Button>Select files</Button>
</Upload>
<Upload.Dragger action="/api/upload" listType="picture">
<p>Drop files here</p>
</Upload.Dragger>
{/* Inside a Form. Form.Item's default getValueFromEvent returns the first
argument whole, and ours is the change info rather than a value — so the
binding has to say which half of it is the value. */}
<Form.Item name="files" valuePropName="fileList" getValueFromEvent={info => info.fileList}>
<Upload action="/api/upload">
<Button>Select files</Button>
</Upload>
</Form.Item><Upload action="/api/upload" multiple accept="image/*" :max-count="5">
<Button>Select files</Button>
</Upload><Upload action="/api/upload" multiple accept="image/*" maxCount={5}>
<Button>Select files</Button>
</Upload><ck-upload action="/api/upload" multiple accept="image/*" [maxCount]="5">
<button ckButton>Select files</button>
</ck-upload>Props
| Prop | Type | Default | Notes |
|---|---|---|---|
fileList, defaultFileList | UploadFile[] | — | The queue, controlled or not. Entries carry uid, name, status and percent. |
onChange | (info: { file: UploadFile; fileList: UploadFile[] }) => void | — | Fires on add, on every progress tick, on settle and on remove. A controlled Upload needs it to move at all. |
action | string | ((file: File) => string | Promise<string>) | — | Where to POST. A function is awaited after the row is already showing as uploading, which is what signed-URL flows need. |
method | "POST" | "PUT" | "POST" | Request method. |
headers | Record<string, string> | — | Extra request headers. |
data | Record<string, string> | ((file: File) => Record<string, string>) | — | Extra multipart fields sent alongside the file. |
name | string | "file" | The multipart FIELD name — not the form field name `name` means on Input, Select and DatePicker. Kept for drop-in compatibility; it is a genuine collision. |
withCredentials | boolean | false | Send cookies cross-origin. |
customRequest | (args: UploadRequestArgs) => { abort: () => void } | void | — | Replaces the built-in transport entirely. Wins over `action`. Return an abort and remove/unmount will call it. |
beforeUpload | (file: File, files: File[]) => boolean | Promise<boolean> | — | `false` — or a rejected promise — lists the file at status `selected` and never uploads it. The second argument is the files that were ADMITTED, not the raw batch: what `accept` and `maxCount` let through. |
multiple | boolean | false | Allow a multi-pick. |
accept | string | — | The `<input accept>` grammar. Re-checked on drop as well, which the attribute cannot do. |
maxCount | number | — | `1` REPLACES the list and drops `multiple` from the dialog; any other value truncates the incoming batch to the room left. The replaced row is aborted, revoked and reported through `onChange` — a replacement is a removal plus an addition. |
disabled | boolean | false | Refuse picks and drops, and disable each row's own Retry and Remove. |
listType | "text" | "picture" | "text" | `picture` shows a thumbnail, minted and revoked by the component. |
showUploadList | boolean | true | Render the list at all. Nothing is emitted when it is off or the list is empty. |
onRemove | (file: UploadFile) => boolean | Promise<boolean> | — | `false` vetoes the removal. Removing aborts an in-flight request first. |
onPreview | (file: UploadFile) => void | — | Makes the file name a button rather than a link. |
directory | boolean | false | Pick a whole folder. Implies `multiple`, and names rows by their folder path. |
Prop names are identical in all four frameworks. Only two-way binding differs, and each framework uses its own idiom over the same underlying prop.
Parts
| data-part | Description |
|---|---|
root | The wrapper. Carries data-list-type and data-disabled. |
trigger | Wraps your children on the plain Upload. Inert — the child is the control. |
dropzone | Upload.Dragger's target. role=button, with Enter and Space. |
input | The hidden file input. Visually hidden, never display:none. |
list | The <ul>. Absent when there is nothing in it. |
item | One row. data-state is selected | uploading | done | error. |
item-name | A button with onPreview, a link with a url, plain text otherwise. |
item-progress | role=progressbar; the fill reads --ck-upload-progress. |
item-actions | Retry and remove, at the inline end. |
status | A visually hidden live region, written only on settle. |