Multi-file drag-and-drop upload area built on react-dropzone. Files are uploaded immediately on drop/selection; Dropzone.List renders the uploaded files with progress and remove controls.
Use Dropzone for uploading one or more files via drag-and-drop or a click-to-browse area. Pair the drop area (Dropzone) with Dropzone.List — both share the same value (a DropzoneFile[]) and onChange so the list stays in sync with what was dropped.
@uxf/form form: use @uxf/form/dropzone instead — it wires react-hook-form (useController), reads the form context, and adds count validation (minFilesCount / maxFilesCount). @uxf/ui/dropzone is the controlled primitive you drive with value / onChange.FileInput.AvatarFileInput.import { FileResponse } from "@uxf/core/types";
import { Dropzone } from "@uxf/ui/dropzone";
import { DropzoneFile } from "@uxf/ui/dropzone/types";
import { getDropzoneState } from "@uxf/ui/utils/get-dropzone-state";
import { useState } from "react";
// your uploader: send the file to storage, resolve with the stored file
declare function uploadFile(file: File): Promise<FileResponse>;
function Example() {
const [files, setFiles] = useState<DropzoneFile[]>([]);
const { status } = getDropzoneState(files);
return (
<>
<Dropzone
isDisabled={status === "UPLOADING"}
label="Use drag and drop or click to upload"
name="attachments"
onChange={setFiles}
onUploadFile={uploadFile}
value={files}
/>
<Dropzone.List name="attachments" onChange={setFiles} value={files} />
</>
);
}
Import from @uxf/ui/dropzone:
| Export | Kind | Description |
|---|---|---|
Dropzone | component | The drop area (DropzoneInput). |
Dropzone.List | component | List of uploaded files (DropzoneList). |
DropzoneInputProps | type | Props of Dropzone. |
DropzoneListProps | type | Props of Dropzone.List. |
Related helpers and types (separate deep imports, not on the component):
getDropzoneState — @uxf/ui/utils/get-dropzone-stateDropzoneFile type — @uxf/ui/dropzone/typesDropzone props (DropzoneInputProps)| Prop | Type | Default | Description |
|---|---|---|---|
value | DropzoneFile[] | undefined | — | Required. Current files (controlled). |
onChange | (value: DropzoneFile[] | undefined, event?) => void | — | Required. Receives the updated file list. |
onUploadFile | (file: File, options?: UploadOptions) => Promise<FileResponse> | — | Required. Uploads a dropped file; called per file with an AbortController and progress callback. |
name | string | — | Required. Field name (also emitted as data-name). |
accept | Accept ({ [mime: string]: string[] }) | — | Accepted MIME types in react-dropzone format, e.g. { "image/*": [] }. |
maxFileSize | number | — | Max size per file in bytes. |
minFileSize | number | — | Min size per file in bytes. |
maxFilesCount | number | — | Max number of files. When 1, the input is single-file (multiple is off). Files past the limit are rejected individually — the ones within it still upload. |
icon | IconName | "cloud" | Icon shown in the drop area. |
label | ReactNode | — | Drop area label. |
helperText | ReactNode | — | Helper / error text under the drop area. |
isNotClickable | boolean | false | Disable click-to-browse (drag only). |
isNotDraggable | boolean | false | Disable dragging (click only). |
onDropRejected | (fileRejections: FileRejection[]) => void | — | Called for files rejected by accept/size/count (react-dropzone FileRejection[]). |
onUploadComplete | (files: FileResponse[]) => Promise<void> | — | Called once all uploads settle, with the successfully uploaded files. |
onUploadError | (err: unknown) => void | — | Called when an individual upload fails. |
isDisabled | boolean | false | Disable the drop area. |
isReadOnly / isInvalid / isRequired / isFocused | boolean | false | State flags (styling / data-*). |
id | string | — | Input id. |
className / style | string / CSSProperties | — | Root styling. |
Dropzone.List props (DropzoneListProps)| Prop | Type | Default | Description |
|---|---|---|---|
value | DropzoneFile[] | undefined | — | Required. Files to render (share with Dropzone). |
onChange | (value: DropzoneFile[] | undefined, event?) => void | — | Required. Receives the list after a removal. |
name | string | — | Required. Field name. |
errorText | string | "File upload error" | Text shown under a file that failed to upload. |
isDownloadableOnClick | boolean | false | Render the file link with download instead of opening in a new tab. |
onRemoveConfirm | (file: DropzoneFile) => Promise<boolean> | — | Confirm before removing; remove only if it resolves true. |
renderItem | (file, onRemove, isUploading) => ReactNode | — | Custom renderer for each list item (replaces the default row). |
isDisabled | boolean | false | Hide the per-item remove buttons. |
className / style | string / CSSProperties | — | List styling. |
getDropzoneStateimport { getDropzoneState } from "@uxf/ui/utils/get-dropzone-state";
const { status, errorMessage } = getDropzoneState(files);
// status: "OK" | "UPLOADING" | "ERROR"
Derives the overall upload state from the file list. Use status === "UPLOADING" to disable the drop area while files are in flight.
DropzoneFileExtends FileResponse (@uxf/core/types) with upload bookkeeping:
| Field | Type | Description |
|---|---|---|
originalFile | File | The picked file (present until the server response replaces it). |
progress | number | null | Upload progress 0–100, or null when not computable. |
error | unknown | Set when the file's upload failed. |
abortController | AbortController | Aborts the in-flight upload when the file is removed. |
id and a progress value until its onUploadFile promise resolves and the server FileResponse replaces it.abortController.abort().onDropRejected fires when react-dropzone rejects files (wrong type, too large/small, too many). Rejection is per file, not per batch: dropping more files than maxFilesCount uploads the ones within the limit and reports only the surplus as too-many-files. A ready-made handler exists at @uxf/ui/dropzone/handle-rejected-files (handleRejectedFiles), but it shows hardcoded Czech alert() messages — prefer your own handler in production.UiContext that provides domain, already-uploaded file names in Dropzone.List render as links to the stored file.Client component ("use client").
Import the required stylesheets once in your global CSS:
@import url("@uxf/ui/css/icon.css");
@import url("@uxf/ui/css/dropzone.css");
Also requires the global @uxf/ui token layer, set up once per app — see @uxf/ui setup.