React hooks for file uploads, built on top of @designbycode/uploader-core.
- useUploader — Manages upload queue with React state
- useDropzone — Drag & drop zone with file filtering
- useFileItem — Extracts file item properties with preview support
- useFilePreview — Standalone hook for image previews
- Framework-agnostic — Built on the core uploader library
- TypeScript — Full TypeScript support
# Using bun
bun add @designbycode/uploader-react @designbycode/uploader-core
# Using npm
npm install @designbycode/uploader-react @designbycode/uploader-core
# Using pnpm
pnpm add @designbycode/uploader-react @designbycode/uploader-core"use client";
import {
useUploader,
useDropzone,
useFileItem,
} from "@designbycode/uploader-react";
export function FileUploader() {
const {
files,
addFiles,
uploadAll,
removeFile,
cancelFile,
totalProgress,
queuedCount,
uploadingCount,
successCount,
errorCount,
} = useUploader({
autoUpload: true,
maxConcurrent: 2,
validation: {
maxSize: 10 * 1024 * 1024,
acceptedMimeTypes: ["image/png", "image/jpeg"],
},
process: async (file, { signal, onProgress }) => {
const formData = new FormData();
formData.append("file", file);
// Upload logic here
return { serverId: "uploaded-file-id" };
},
});
const { isDragging, getRootProps, getInputProps } = useDropzone({
onDrop: addFiles,
acceptedMimeTypes: ["image/png", "image/jpeg"],
maxSize: 10 * 1024 * 1024,
});
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
{isDragging ? "Drop files here" : "Click or drag to upload"}
</div>
);
}Main hook for managing uploads.
const {
files, // UploadFile[]
addFiles, // (files: File[]) => Promise<UploadFile[]>
uploadAll, // () => void
uploadFile, // (id: string) => void
removeFile, // (id: string) => Promise<void>
cancelFile, // (id: string) => void
cancelAll, // () => void
clear, // () => void
getFile, // (id: string) => UploadFile | undefined
getFileByServerId, // (serverId: string) => UploadFile | undefined
totalProgress, // number (0-100)
queuedCount, // number
uploadingCount, // number
successCount, // number
errorCount, // number
} = useUploader(options);Inherits all options from uploader-core.
Hook for drag & drop file selection.
const {
isDragging, // boolean
getRootProps, // () => div props
getInputProps, // () => input props
} = useDropzone({
onDrop: (files) => void,
acceptedMimeTypes?: string[],
maxSize?: number,
multiple?: boolean,
})function DropZone({ onFilesSelected }) {
const { isDragging, getRootProps, getInputProps } = useDropzone({
onDrop: onFilesSelected,
acceptedMimeTypes: ["image/*"],
maxSize: 5 * 1024 * 1024,
});
return (
<div {...getRootProps()} className={isDragging ? "dragging" : ""}>
<input {...getInputProps()} />
<p>{isDragging ? "Drop here!" : "Click or drag files"}</p>
</div>
);
}Helper hook to extract file item properties with automatic preview generation for images.
const {
id,
name,
size,
type,
progress,
status,
error,
serverId,
preview, // string | undefined (blob URL for images)
isImage, // boolean
cancel,
remove,
} = useFileItem({ file, removeFile, cancelFile, generatePreview: true });function FileItem({ file, onRemove, onCancel }) {
const { name, progress, status, cancel, remove } = useFileItem({
file,
removeFile: onRemove,
cancelFile: onCancel,
});
return (
<div>
<span>{name}</span>
{status === "uploading" && (
<div>
<progress value={progress} max={100} />
<button onClick={cancel}>Cancel</button>
</div>
)}
<button onClick={remove}>Remove</button>
</div>
);
}Standalone hook for generating image previews.
const {
preview, // string | null
generatePreview, // () => void
revokePreview, // () => void
isGenerating, // boolean
isImage, // boolean
} = useFilePreview(file, { autoPreview: true });function ImagePreview({ file }) {
const { preview, isImage } = useFilePreview(file, { autoPreview: true });
if (!isImage) return null;
return preview ? <img src={preview} alt={file.name} /> : null;
}"use client";
import {
useUploader,
useDropzone,
useFileItem,
} from "@designbycode/uploader-react";
function FileList({ files, onRemove, onCancel }) {
return (
<ul>
{files.map((file) => (
<li key={file.id}>
<FileItem file={file} onRemove={onRemove} onCancel={onCancel} />
</li>
))}
</ul>
);
}
function FileItem({ file, onRemove, onCancel }) {
const { name, progress, status, cancel, remove } = useFileItem({
file,
removeFile: onRemove,
cancelFile: onCancel,
});
return (
<div>
<span>{name}</span>
{status === "uploading" && (
<div>
<span>{progress}%</span>
<button onClick={cancel}>Cancel</button>
</div>
)}
{status === "success" && <span>Done</span>}
{status === "error" && <span>Failed</span>}
<button onClick={remove}>Remove</button>
</div>
);
}
export default function Uploader() {
const uploader = useUploader({
maxConcurrent: 2,
process: async (file, { onProgress }) => {
// Upload logic
return { serverId: "id" };
},
});
const dropzone = useDropzone({
onDrop: uploader.addFiles,
});
return (
<div>
<div {...dropzone.getRootProps()}>
<input {...dropzone.getInputProps()} />
<p>{dropzone.isDragging ? "Drop!" : "Click or drag"}</p>
</div>
<div>
<span>Queued: {uploader.queuedCount}</span>
<span>Uploading: {uploader.uploadingCount}</span>
<span>Done: {uploader.successCount}</span>
<span>Failed: {uploader.errorCount}</span>
</div>
{uploader.queuedCount > 0 && (
<button onClick={uploader.uploadAll}>Upload All</button>
)}
<FileList
files={uploader.files}
onRemove={uploader.removeFile}
onCancel={uploader.cancelFile}
/>
</div>
);
}MIT