Batch Upload
Collect multiple files and upload them all at once in a single request.
Previewmock transport
Add files, then upload them together as one batch.
Code
import { useCallback, useRef, useState } from "react";import {UplofilePreview,UplofileRoot,UplofileTrigger,type UploadStatus,} from "@/components/ui/uplofile";import { BatchFileItem } from "./batchupload.batchfileitem.demo.tsx";type BatchStatus = Extract<UploadStatus,"idle" | "uploading" | "done" | "error">;type PendingUpload = {file: File;resolve: (value: { id: string; url: string }) => void;reject: (reason: Error) => void;setProgress?: (progress: number) => void;};export default function BatchUploadDemo() {const [status, setStatus] = useState<BatchStatus>("idle");const [progress, setProgress] = useState(0);const pendingUploads = useRef(new Map<File, PendingUpload>());const queueFile = useCallback((file: File,signal: AbortSignal,setFileProgress?: (progress: number) => void,) =>new Promise<{ id: string; url: string }>((resolve, reject) => {const pending = { file, resolve, reject, setProgress: setFileProgress };pendingUploads.current.set(file, pending);signal.addEventListener("abort",() => {pendingUploads.current.delete(file);reject(new Error("Upload cancelled"));},{ once: true },);}),[],);const uploadBatch = useCallback(async (files: File[]) => {if (files.length === 0) return;setStatus("uploading");setProgress(0);try {for (const [index, file] of files.entries()) {const pending = pendingUploads.current.get(file);if (!pending) continue;await new Promise<void>((resolve) => {let fileProgress = 0;const interval = window.setInterval(() => {fileProgress = Math.min(fileProgress + 10, 100);pending.setProgress?.(fileProgress);setProgress(Math.round(((index + fileProgress / 100) / files.length) * 100),);if (fileProgress === 100) {window.clearInterval(interval);resolve();}}, 80);});pending.resolve({id: file.name,url: `https://example.com/uploads/${encodeURIComponent(file.name)}`,});pendingUploads.current.delete(file);}setStatus("done");} catch {setStatus("error");}}, []);return (<UplofileRoot upload={queueFile} multiple accept="*/*"><UplofilePreviewrender={({ items }) => {const files = items.flatMap((item) => (item.file ? [item.file] : []));return (<div className="space-y-4"><div className="rounded-xl border border-border bg-muted/30 p-4"><div className="flex flex-wrap gap-2"><UplofileTrigger asChild><button className="rounded-lg border border-border bg-background px-3 py-2 text-sm font-medium">Add files</button></UplofileTrigger><buttontype="button"onClick={() => uploadBatch(files)}disabled={files.length === 0 || status === "uploading"}className="rounded-lg bg-primary px-3 py-2 text-sm font-semibold text-primary-foreground disabled:opacity-50">Upload batch{files.length ? ` (${files.length})` : ""}</button></div>{status !== "idle" && (<div className="mt-4 space-y-2"><div className="flex justify-between text-xs text-muted-foreground"><span>{status}</span><span>{progress}%</span></div><div className="h-2 overflow-hidden rounded-full bg-secondary"><divclassName="h-full bg-primary transition-all"style={{ width: `${progress}%` }}/></div></div>)}</div><div className="divide-y overflow-hidden rounded-xl border border-border bg-card">{items.length === 0 ? (<p className="p-8 text-center text-sm text-muted-foreground">Add files, then upload them together as one batch.</p>) : (items.map((item) => (<BatchFileItem key={item.uid} item={item} />)))}</div></div>);}}/></UplofileRoot>);}
Notes
- The
uploadfunction defers resolution until a batch trigger resolves all pending promises. - A Upload All button drains the queue and sends all files as one batch.
useUplofileis not needed — pending state is tracked outside the library via a ref.- Abort handling works normally: cancelling a pending file removes it from the batch queue.