React component for file upload with AJAX, drag-and-drop, and directory support
npx @tessl/cli install tessl/npm-rc-upload@4.10.0React Upload component with support for AJAX uploads, drag-and-drop, directory uploads, and multiple upload methods. Provides comprehensive file upload functionality with extensive customization options and backward compatibility.
npm install rc-uploadimport Upload, { UploadProps } from "rc-upload";For CommonJS:
const Upload = require("rc-upload");
const { UploadProps } = require("rc-upload"); // Type only available in TypeScriptimport Upload from "rc-upload";
// Basic file upload
<Upload
action="https://jsonplaceholder.typicode.com/posts/"
accept=".jpg,.png,.gif"
multiple
onStart={(file) => {
console.log('Upload started:', file.name);
}}
onSuccess={(response, file) => {
console.log('Upload successful:', file.name, response);
}}
onError={(error, response, file) => {
console.log('Upload failed:', error);
}}
>
<button>Click to Upload</button>
</Upload>
// Advanced usage with custom request
<Upload
customRequest={({ file, onSuccess, onError, onProgress }) => {
const formData = new FormData();
formData.append('file', file);
fetch('/api/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => onSuccess(data, file))
.catch(error => onError(error));
}}
directory
onStart={(file) => console.log('Started:', file.name)}
>
<div>Drag files or folders here</div>
</Upload>The main React component that provides file upload functionality with drag-and-drop support, AJAX uploads, and extensive customization options.
/**
* Main Upload component providing comprehensive file upload functionality
*/
class Upload extends React.Component<UploadProps> {
/**
* Abort upload for a specific file
* @param file - The file to abort upload for
*/
abort(file: RcFile): void;
}
export default Upload;Core configuration properties for controlling upload behavior, validation, and customization.
interface UploadProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onError' | 'onProgress'> {
/** Upload URL - can be string or function returning URL/Promise<URL> */
action?: Action;
/** HTTP method for upload request */
method?: UploadRequestMethod;
/** Additional form data to include with upload */
data?: Record<string, unknown> | ((file: RcFile | string | Blob) => Record<string, unknown>);
/** Custom HTTP headers */
headers?: UploadRequestHeader;
/** Include credentials in CORS requests */
withCredentials?: boolean;
/** Custom upload implementation */
customRequest?: (option: UploadRequestOption) => void | { abort: () => void };
/** File type restrictions (MIME types or extensions) */
accept?: string;
/** Allow multiple file selection */
multiple?: boolean;
/** Enable directory upload (deprecated, use folder instead) */
directory?: boolean;
/** Enable directory/folder upload */
folder?: boolean;
/** Enable paste-to-upload functionality */
pastable?: boolean;
/** Wrapper component type */
component?: React.ComponentType<any> | string;
/** CSS class name */
className?: string;
/** Inline styles */
style?: React.CSSProperties;
/** CSS class prefix */
prefixCls?: string;
/** Element ID */
id?: string;
/** Disable upload functionality */
disabled?: boolean;
/** Open file dialog on click */
openFileDialogOnClick?: boolean;
/** Whether control elements are inside component */
hasControlInside?: boolean;
/** Nested class names */
classNames?: {
input?: string;
};
/** Nested styles */
styles?: {
input?: React.CSSProperties;
};
/** Pre-upload validation/transformation hook */
beforeUpload?: (file: RcFile, FileList: RcFile[]) => BeforeUploadFileType | Promise<void | BeforeUploadFileType> | void;
/** Called when file upload starts */
onStart?: (file: RcFile) => void;
/** Called during upload progress */
onProgress?: (event: UploadProgressEvent, file: RcFile) => void;
/** Called on successful upload */
onSuccess?: (response: Record<string, unknown>, file: RcFile, xhr: XMLHttpRequest) => void;
/** Called on upload error */
onError?: (error: Error, ret: Record<string, unknown>, file: RcFile) => void;
/** Called when batch upload starts */
onBatchStart?: (fileList: Array<{ file: RcFile; parsedFile: Exclude<BeforeUploadFileType, boolean> }>) => void;
/** Custom click handler */
onClick?: (e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
/** Mouse enter handler */
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement>) => void;
/** Mouse leave handler */
onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;
}Core type definitions for files, upload requests, and configuration options.
/**
* Enhanced File interface with unique identifier
*/
interface RcFile extends File {
/** Unique identifier for the file */
uid: string;
}
/**
* Upload request configuration and callbacks
*/
interface UploadRequestOption<T = any> {
/** Upload progress callback */
onProgress?: (event: UploadProgressEvent, file?: UploadRequestFile) => void;
/** Upload error callback */
onError?: (event: UploadRequestError | ProgressEvent, body?: T) => void;
/** Upload success callback */
onSuccess?: (body: T, fileOrXhr?: UploadRequestFile | XMLHttpRequest) => void;
/** Additional form data */
data?: Record<string, unknown>;
/** Target filename */
filename?: string;
/** File to upload */
file: UploadRequestFile;
/** Include credentials */
withCredentials?: boolean;
/** Upload URL */
action: string;
/** HTTP headers */
headers?: UploadRequestHeader;
/** HTTP method */
method: UploadRequestMethod;
}
/**
* Upload progress event with percentage
*/
interface UploadProgressEvent extends Partial<ProgressEvent> {
/** Upload progress percentage (0-100) */
percent?: number;
}
/**
* Enhanced error interface for upload failures
*/
interface UploadRequestError extends Error {
/** HTTP response status */
status?: number;
/** HTTP method used */
method?: UploadRequestMethod;
/** Request URL */
url?: string;
}Utility type definitions used throughout the upload component.
/** Upload URL - string or function returning URL */
type Action = string | ((file: RcFile) => string | PromiseLike<string>);
/** HTTP methods supported for upload */
type UploadRequestMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
/** HTTP headers object */
type UploadRequestHeader = Record<string, string>;
/** Return type for beforeUpload hook */
type BeforeUploadFileType = File | Blob | boolean | string;
/** File type for upload requests */
type UploadRequestFile = Exclude<BeforeUploadFileType, File | boolean> | RcFile;import Upload from "rc-upload";
<Upload
directory
action="/api/upload"
onStart={(file) => {
console.log('Starting upload:', file.name);
console.log('File path:', file.webkitRelativePath); // Available for directory uploads
}}
onSuccess={(response, file) => {
console.log('Upload completed:', file.name);
}}
>
<div style={{ padding: '20px', border: '2px dashed #ccc' }}>
Click or drag folders here
</div>
</Upload>import Upload from "rc-upload";
const customUpload = ({ file, onSuccess, onError, onProgress }) => {
const formData = new FormData();
formData.append('file', file);
formData.append('userId', '123');
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
onProgress({ percent: (e.loaded / e.total) * 100 });
}
});
xhr.addEventListener('load', () => {
if (xhr.status === 200) {
onSuccess(JSON.parse(xhr.responseText), file);
} else {
onError(new Error(`Upload failed: ${xhr.status}`));
}
});
xhr.addEventListener('error', () => {
onError(new Error('Network error'));
});
xhr.open('POST', '/api/upload');
xhr.send(formData);
};
<Upload customRequest={customUpload}>
<button>Upload with Custom Handler</button>
</Upload>import Upload from "rc-upload";
const validateFile = (file, fileList) => {
// Check file size (max 5MB)
if (file.size > 5 * 1024 * 1024) {
console.error('File too large');
return false; // Reject file
}
// Check file type
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (!allowedTypes.includes(file.type)) {
console.error('Invalid file type');
return false;
}
// Transform file name
const newFile = new File([file], `prefix_${file.name}`, {
type: file.type,
lastModified: file.lastModified,
});
return newFile; // Return transformed file
};
<Upload
action="/api/upload"
accept=".jpg,.png,.gif"
beforeUpload={validateFile}
onError={(error, response, file) => {
console.error('Upload error:', error.message);
}}
>
<button>Upload Images Only</button>
</Upload>import Upload from "rc-upload";
import { useState } from "react";
const DragUpload = () => {
const [dragOver, setDragOver] = useState(false);
return (
<Upload
action="/api/upload"
multiple
onStart={() => setDragOver(false)}
onMouseEnter={() => setDragOver(true)}
onMouseLeave={() => setDragOver(false)}
style={{
display: 'block',
width: '300px',
height: '200px',
border: `2px dashed ${dragOver ? '#007acc' : '#ccc'}`,
borderRadius: '8px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer',
backgroundColor: dragOver ? '#f0f8ff' : '#fafafa'
}}
>
<div>
<p>📁 Drop files here or click to upload</p>
<p style={{ fontSize: '12px', color: '#666' }}>
Supports multiple files and drag & drop
</p>
</div>
</Upload>
);
};