File Schema - Copy this React, Tailwind Component to your project
import-{-useForm-}-from-"react-hook-form";-import-{-useCallback,-useState-}-from-"react";-import-{-useDropzone-}-from-"react-dropzone";-import-{-zodResolver-}-from-"@hookform/resolvers/zod";-import-{-z-}-from-"zod";-const-MAX_FILE_SIZE-=-5-*-1024-*-1024;-//-5MB-const-ACCEPTED_IMAGE_TYPES-=-["image/jpeg",-"image/jpg",-"image/png"];-const-MAX_FILES-=-5;-//-Maximum-number-of-files-allowed-const-schema-=-z.object({-files:-z-.array(-z.object({-file:-z.any().refine(-(file)-=>-file.size-<=-MAX_FILE_SIZE,-"Max-image-size-is-5MB."-),-})-)-.max(MAX_FILES,-`You-can-only-upload-up-to-${MAX_FILES}-images.`)-.refine(-(files)-=>-files.every((f)-=>-ACCEPTED_IMAGE_TYPES.includes(f.file.type)),-"Only-.jpg,-.jpeg,-and-.png-formats-are-supported."-),-});-const-MultiFileUpload-=-()-=>-{-const-[previews,-setPreviews]-=-useState([]);-//-Array-of-previews-const-{-handleSubmit,-formState:-{-errors-},-setValue,-watch,-}-=-useForm({-resolver:-zodResolver(schema),-defaultValues:-{-files:-[],-},-});-const-onDrop-=-useCallback(-(droppedFiles)-=>-{-const-previousFiles-=-watch("files")-||-[];-//-Get-the-current-files-array-const-newFiles-=-[-...previousFiles,-...droppedFiles-.slice(0,-MAX_FILES---previousFiles.length)-.map((file)-=>-({-file-})),-];-//-Update-react-hook-form-state-setValue("files",-newFiles,-{-shouldValidate:-true-});-//-Update-preview-state-setPreviews((prev)-=>-[-...prev,-...droppedFiles-.slice(0,-MAX_FILES---prev.length)-.map((file)-=>-({-file,-preview:-URL.createObjectURL(file)-})),-]);-},-[setValue,-watch]-);-const-{-getRootProps,-getInputProps,-isDragActive-}-=-useDropzone({-onDrop,-accept:-ACCEPTED_IMAGE_TYPES.join(","),-maxFiles:-MAX_FILES,-maxSize:-MAX_FILE_SIZE,-});-const-watchFiles-=-watch("files");-const-onSubmit-=-(data)-=>-{-console.log("Submitted-Files:",-data.files);-//-Clean-up-previews-previews.forEach(({-preview-})-=>-URL.revokeObjectURL(preview));-setPreviews([]);-setValue("files",-[]);-};-const-removeFile-=-(index)-=>-{-const-updatedFiles-=-watchFiles.filter((_,-i)-=>-i-!==-index);-setValue("files",-updatedFiles,-{-shouldValidate:-true-});-setPreviews((prev)-=>-prev.filter((_,-i)-=>-i-!==-index));-};-return-(-<div-className="max-w-xl-mx-auto-p-6">-<form-onSubmit={handleSubmit(onSubmit)}-className="space-y-6"-noValidate>-<div-{...getRootProps()}-className={`relative-border-2-border-dashed-rounded-lg-p-6-cursor-pointer-transition-colors-${-isDragActive-?-"bg-blue-50-border-blue-500"-:-"border-gray-300-hover:border-blue-400"-}-${errors.files-?-"border-red-500-bg-red-50"-:-""}`}->-<input-{...getInputProps()}-/>-<div-className="flex-flex-col-items-center-justify-center-space-y-3">-<div-className="text-center">-<p-className="text-gray-600">-Drag-&-drop-your-images-here,-or{"-"}-<span-className="text-blue-500">browse</span>-</p>-<p-className="text-sm-text-gray-500-mt-1">-Supports:-JPG,-JPEG,-PNG-(Max-{MAX_FILES}-images,-Max-5MB-each)-</p>-</div>-</div>-</div>-{errors.files-&&-(-<div-className="flex-items-center-space-x-2-text-red-500">-<span-className="text-sm">{errors.files.message}</span>-</div>-)}-{/*-File-Previews-*/}-{previews.length->-0-&&-(-<div-className="mt-4-space-y-4">-<p-className="text-sm-font-medium-text-gray-700">Previews:</p>-<div-className="grid-grid-cols-2-gap-4">-{previews.map(({-file,-preview-},-index)-=>-(-<div-key={index}-className="relative-w-[150px]-h-[150px]-rounded-lg-overflow-hidden-border-border-gray-200"->-<img-src={preview}-alt="Upload-preview"-className="w-full-h-full-object-cover"-/>-<button-type="button"-onClick={()-=>-removeFile(index)}-className="absolute-top-1-right-1-bg-red-500-text-white-p-1-rounded-full"->-×-</button>-</div>-))}-</div>-</div>-)}-<button-type="submit"-className="w-full-bg-blue-500-text-white-py-2-px-4-rounded-lg-hover:bg-blue-600-transition-colors-disabled:opacity-50-disabled:cursor-not-allowed"-disabled={!watchFiles-||-watchFiles.length-===-0-||-errors.files}->-Upload-Images-</button>-</form>-</div>-);-};-export-default-MultiFileUpload;
