Uplofile is open sourceStar on GitHub

Before Upload Validation

Validate or enrich files before they are added to the state and uploaded.

Preview

Validation: Max 2MB, no "restricted" in filename.

No files selected

Code

1import {
2 UplofileRoot,
3 UplofileTrigger,
4 UplofilePreview,
5 type UploadFileItem,
6} from "@/components/ui/uplofile";
7import { IoDocumentOutline, IoCheckmarkCircleOutline, IoReloadOutline, IoAlertCircleOutline } from "react-icons/io5";
8import { mockUpload } from "@/lib/utils.ts";
9import { type BeforeUploadFn } from "uplofile";
10
11const beforeUpload: BeforeUploadFn = async (items: UploadFileItem[]) => {
12 return items.map((item) => {
13 // Example: Reject files larger than 2MB
14 if (item.file && item.file.size > 2 * 1024 * 1024) {
15 return {
16 uid: item.uid,
17 valid: false,
18 reason: "File too large (max 2MB)",
19 };
20 }
21
22 // Example: Reject specific file names (e.g., restricted keywords)
23 if (item.name.toLowerCase().includes("restricted")) {
24 return {
25 uid: item.uid,
26 valid: false,
27 reason: "File name contains restricted words",
28 };
29 }
30
31 return { uid: item.uid, valid: true };
32 });
33};
34
35export default function BeforeUploadValidationDemo() {
36 return (
37 <UplofileRoot upload={mockUpload} beforeUpload={beforeUpload}>
38 <div className="space-y-4">
39 <p className="text-sm text-muted-foreground">
40 Validation: Max 2MB, no "restricted" in filename.
41 </p>
42 <UplofileTrigger asChild>
43 <button className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 shadow">
44 Select Files
45 </button>
46 </UplofileTrigger>
47
48 <UplofilePreview
49 render={({ items }) => (
50 <div className="mt-6 space-y-3">
51 {items.length === 0 ? (
52 <div className="text-center py-4 border-2 border-dashed rounded-lg bg-muted/5">
53 <p className="text-muted-foreground text-sm">
54 No files selected
55 </p>
56 </div>
57 ) : (
58 <div className="grid gap-2">
59 {items.map((item) => (
60 <ValidationFileItem key={item.uid} item={item} />
61 ))}
62 </div>
63 )}
64 </div>
65 )}
66 />
67 </div>
68 </UplofileRoot>
69 );
70}
71
72function ValidationFileItem({ item }: { item: UploadFileItem }) {
73 return (
74 <div
75 className={`flex flex-col p-3 rounded-lg border bg-card text-card-foreground shadow-sm animate-in fade-in slide-in-from-top-1 ${item.status === "error" ? "border-destructive/50 bg-destructive/5" : ""}`}
76 >
77 <div className="flex items-center justify-between">
78 <div className="flex items-center gap-3 overflow-hidden">
79 <div
80 className={`p-2 rounded-md ${item.status === "error" ? "bg-destructive/10 text-destructive" : "bg-primary/10 text-primary"}`}
81 >
82 <IoDocumentOutline className="h-4 w-4" />
83 </div>
84 <div className="grid gap-0.5 overflow-hidden">
85 <span className="text-sm font-medium truncate max-w-[200px] sm:max-w-[400px]">
86 {item.name}
87 </span>
88 </div>
89 </div>
90 <div className="flex items-center gap-2 ml-4">
91 {item.status === "uploading" && (
92 <IoReloadOutline className="h-4 w-4 animate-spin text-muted-foreground" />
93 )}
94 {item.status === "done" && (
95 <IoCheckmarkCircleOutline className="h-4 w-4 text-emerald-500" />
96 )}
97 {item.status === "error" && (
98 <IoAlertCircleOutline className="h-4 w-4 text-destructive" />
99 )}
100 </div>
101 </div>
102
103 {item.status === "error" && item.error && (
104 <p className="mt-2 text-xs text-destructive font-medium flex items-center gap-1">
105 {item.error}
106 </p>
107 )}
108
109 {item.status === "uploading" && (
110 <div className="mt-3 w-full bg-secondary rounded-full h-1.5 overflow-hidden">
111 <div
112 className="bg-primary h-full transition-all duration-300 ease-in-out"
113 style={{ width: `${item.progress}%` }}
114 />
115 </div>
116 )}
117 </div>
118 );
119}

Key Points

  • Use the beforeUpload prop on UplofileRoot
  • Supports asynchronous validation (e.g., checking image dimensions)
  • Return false to reject the entire batch
  • Return an array of objects to provide granular control and error reasons
  • Files rejected with a reason are added to state with "error" status