Batch Upload
Collect multiple files and upload them all at once in a single request.
Preview
Add files, then upload them together as one batch.
Code
1import { useCallback, useState } from "react";2import {3 UplofilePreview,4 UplofileRoot,5 UplofileTrigger,6 type UploadFileItem,7 type UploadStatus,8} from "@/components/ui/uplofile";9import { mockUpload } from "@/lib/utils.ts";1011type BatchStatus = Extract<UploadStatus, "idle" | "uploading" | "done" | "error">;1213const queueFile = async (file: File) => ({14 id: file.name,15 url: URL.createObjectURL(file),16});1718export default function BatchUploadDemo() {19 const [status, setStatus] = useState<BatchStatus>("idle");20 const [progress, setProgress] = useState(0);2122 const uploadBatch = useCallback(async (files: File[]) => {23 if (files.length === 0) return;2425 setStatus("uploading");26 setProgress(0);2728 try {29 await mockBatchUpload(files, setProgress);30 setStatus("done");31 } catch {32 setStatus("error");33 }34 }, []);3536 return (37 <UplofileRoot upload={queueFile} multiple accept="*/*">38 <UplofilePreview39 render={({ items }) => {40 const files = items.flatMap((item) => (item.file ? [item.file] : []));4142 return (43 <div className="space-y-4">44 <div className="rounded-xl border border-border bg-muted/30 p-4">45 <div className="flex flex-wrap gap-2">46 <UplofileTrigger asChild>47 <button className="rounded-lg border border-border bg-background px-3 py-2 text-sm font-medium">48 Add files49 </button>50 </UplofileTrigger>5152 <button53 type="button"54 onClick={() => uploadBatch(files)}55 disabled={files.length === 0 || status === "uploading"}56 className="rounded-lg bg-primary px-3 py-2 text-sm font-semibold text-primary-foreground disabled:opacity-50"57 >58 Upload batch{files.length ? ` (${files.length})` : ""}59 </button>60 </div>6162 {status !== "idle" && (63 <div className="mt-4 space-y-2">64 <div className="flex justify-between text-xs text-muted-foreground">65 <span>{status}</span>66 <span>{progress}%</span>67 </div>68 <div className="h-2 overflow-hidden rounded-full bg-secondary">69 <div70 className="h-full bg-primary transition-all"71 style={{ width: `${progress}%` }}72 />73 </div>74 </div>75 )}76 </div>7778 <div className="divide-y overflow-hidden rounded-xl border border-border bg-card">79 {items.length === 0 ? (80 <p className="p-8 text-center text-sm text-muted-foreground">81 Add files, then upload them together as one batch.82 </p>83 ) : (84 items.map((item) => <BatchFileItem key={item.uid} item={item} />)85 )}86 </div>87 </div>88 );89 }}90 />91 </UplofileRoot>92 );93}9495async function mockBatchUpload(96 files: File[],97 setProgress: (progress: number) => void,98) {99 await mockUpload(files[0], undefined, setProgress);100101 return files.map((file) => ({102 id: file.name,103 url: `https://example.com/uploads/${encodeURIComponent(file.name)}`,104 }));105}106107function BatchFileItem({ item }: { item: UploadFileItem }) {108 return (109 <div className="p-3">110 <p className="truncate text-sm font-medium">{item.name}</p>111 </div>112 );113}
Key Points
- → 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.