react-file-upload-kit
v1.0.5
Published
A customizable React file upload kit with drag & drop, validation, and progress.
Maintainers
Readme
react-file-upload-kit
A comprehensive, feature-rich React file upload component library with enterprise-grade capabilities. Built with TypeScript, fully customizable, and production-ready.
✨ Features
Core Features
- ✅ Drag & Drop - Intuitive drag-and-drop file upload
- ✅ Click to Upload - Traditional file picker support
- ✅ Multiple Files - Upload single or multiple files
- ✅ File Validation - Size, type, and count validation
- ✅ Duplicate Detection - Automatic duplicate file filtering
- ✅ Progress Tracking - Real-time upload progress per file
- ✅ Toast Notifications - Beautiful toast notifications for all events
- ✅ File Removal - Remove files before or after upload
- ✅ Custom Styling - Fully customizable colors and themes
- ✅ Dark Mode - Built-in dark theme support
- ✅ React Hook Form - Seamless integration with react-hook-form
- ✅ TypeScript - Full TypeScript support
Advanced Features
- 🖼️ Image Preview - Thumbnail previews with fullscreen view
- 🔄 Retry Failed Uploads - One-click retry for failed uploads
- ⏸️ Pause/Resume - Pause and resume uploads
- 📦 Batch Operations - Select all, delete selected, clear completed
- 🔍 Search/Filter - Search files by name or type
- 📋 Grid/List View - Toggle between grid and list layouts
- ✏️ File Rename - Rename files before upload
- 🏷️ File Tags - Add tags and categories to files
- 📝 File Metadata - Edit file metadata (description, date, custom fields)
- 🔗 Copy URL - Copy uploaded file URLs to clipboard
- 📥 Download Preview - Download file previews
- 🗜️ Image Compression - Compress images before upload
- 🔐 File Encryption - Encrypt files before upload
- 📊 Chunked Upload - Split large files into chunks
- ⚡ Upload Speed - Real-time upload speed indicator
- ⏱️ ETA Display - Estimated time remaining for uploads
- 🔄 Concurrent Uploads - Control concurrent upload limit
- 💾 Progress Persistence - Save and resume uploads after page refresh
- 🔌 WebSocket Progress - Real-time progress via WebSocket
- 🎯 Custom Validation - User-defined validation rules
- 🔀 Drag to Reorder - Reorder files by dragging
- 📄 PDF Preview - Full-screen PDF preview support
📦 Installation
# Using npm
npm install react-file-upload-kit react-hook-form
# Using yarn
yarn add react-file-upload-kit react-hook-form
# Using pnpm
pnpm add react-file-upload-kit react-hook-formPeer Dependencies
react>= 17.0.0react-dom>= 17.0.0react-hook-form>= 7.0.0 (optional, for form integration)
🚀 Quick Start
Basic Usage
import { FileUploader } from 'react-file-upload-kit';
import 'react-file-upload-kit/styles'; // Import CSS
function App() {
const handleUpload = async (files: File[]) => {
// Your upload logic here
const formData = new FormData();
files.forEach(file => formData.append('files', file));
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
return data.files.map((file: any) => ({
name: file.name,
size: file.size,
type: file.type,
url: file.url
}));
};
return (
<FileUploader
onUpload={handleUpload}
multiple={true}
maxSizeMB={10}
/>
);
}CSS Import
You can import the CSS in two ways:
// Recommended: Clean import path
import 'react-file-upload-kit/styles';
// Alternative: Direct path
import 'react-file-upload-kit/dist/index.css';📚 Complete Feature Guide
1. Basic Configuration
<FileUploader
onUpload={handleUpload}
multiple={true} // Allow multiple files
maxSizeMB={50} // Maximum file size in MB
maxFiles={10} // Maximum number of files
accept={['.pdf', '.jpg']} // Allowed file types
disabled={false} // Disable the uploader
theme="light" // "light" | "dark"
/>2. Image Preview
Automatically shows thumbnail previews for image files:
<FileUploader
onUpload={handleUpload}
showImagePreview={true} // Enable image previews (default: true)
/>- Click on image thumbnails to view fullscreen
- Supports: JPG, PNG, GIF, SVG, WebP, etc.
3. Toast Notifications
Beautiful toast notifications for all events:
<FileUploader
onUpload={handleUpload}
showToasts={true} // Enable toasts (default: true)
/>Toast types:
- ✅ Success - Files uploaded successfully
- ❌ Error - Upload failed
- ⚠️ Warning - Validation errors
- ℹ️ Info - General updates
4. Retry Failed Uploads
Automatic retry button for failed uploads:
<FileUploader
onUpload={handleUpload}
// Retry button appears automatically on failed uploads
/>Click the 🔄 button to retry failed uploads.
5. Pause/Resume Uploads
Pause and resume uploads in progress:
<FileUploader
onUpload={handleUpload}
enablePauseResume={true} // Enable pause/resume (default: false)
/>- ⏸️ Pause button appears during upload
- ▶️ Resume button appears for paused uploads
6. Manual Upload Trigger
Disable auto-upload and add manual upload buttons:
<FileUploader
onUpload={handleUpload}
autoUpload={false} // Disable auto-upload
// Shows "Upload All" and "Upload Selected" buttons
/>7. Batch Operations
Select and manage multiple files:
<FileUploader
onUpload={handleUpload}
enableBatchOperations={true} // Enable batch ops (default: true)
/>Features:
- ☑️ Select All checkbox
- 📤 Upload Selected button
- 🗑️ Delete Selected button
- 🧹 Clear Completed button
8. Search/Filter Files
Search files by name or type:
<FileUploader
onUpload={handleUpload}
enableSearch={true} // Enable search (default: false)
/>9. Grid/List View Toggle
Switch between grid and list views:
<FileUploader
onUpload={handleUpload}
enableViewToggle={true} // Enable view toggle (default: false)
defaultView="list" // "grid" | "list" (default: "list")
/>10. File Rename
Rename files before upload:
<FileUploader
onUpload={handleUpload}
enableRename={true} // Enable rename (default: false)
onFileRename={(file, newName) => {
console.log(`Renamed ${file.name} to ${newName}`);
}}
/>11. File Tags
Add tags and categories to files:
<FileUploader
onUpload={handleUpload}
enableTags={true} // Enable tags (default: false)
/>12. File Metadata
Edit file metadata (description, date, custom fields):
<FileUploader
onUpload={handleUpload}
enableMetadata={true} // Enable metadata (default: false)
onMetadataUpdate={(file, metadata) => {
console.log('Metadata updated:', metadata);
}}
/>13. Copy File URL
Copy uploaded file URLs to clipboard:
<FileUploader
onUpload={handleUpload}
enableCopyUrl={true} // Enable copy URL (default: false)
/>14. Image Compression
Compress images before upload:
<FileUploader
onUpload={handleUpload}
enableCompression={true} // Enable compression (default: false)
compressionQuality={0.8} // Quality 0-1 (default: 0.8)
compressionMaxSize={1920} // Max width/height (default: 1920)
/>15. File Encryption
Encrypt files before upload:
<FileUploader
onUpload={handleUpload}
enableEncryption={true} // Enable encryption (default: false)
encryptionKey="your-secret-key" // Required if encryption enabled
/>16. Chunked Upload
Split large files into chunks for better reliability:
<FileUploader
onUpload={handleUpload}
enableChunkedUpload={true} // Enable chunked upload (default: false)
chunkSize={1024 * 1024} // Chunk size in bytes (default: 1MB)
onChunkedUpload={async (file, chunkIndex, chunk, totalChunks) => {
// Upload individual chunk
await uploadChunk(file.name, chunkIndex, chunk);
}}
/>17. Upload Speed & ETA
Display upload speed and estimated time:
<FileUploader
onUpload={handleUpload}
showUploadSpeed={true} // Show speed (default: false)
showETA={true} // Show ETA (default: false)
/>18. Concurrent Upload Limit
Control how many files upload simultaneously:
<FileUploader
onUpload={handleUpload}
maxConcurrentUploads={3} // Max concurrent (default: 3)
/>19. Progress Persistence
Save progress and resume after page refresh:
<FileUploader
onUpload={handleUpload}
enableProgressPersistence={true} // Enable persistence (default: false)
/>20. Custom Validation
Add custom validation rules:
<FileUploader
onUpload={handleUpload}
customValidations={[
{
name: 'no-spaces',
validate: (file) => {
if (file.name.includes(' ')) {
return 'File name cannot contain spaces';
}
return true;
}
},
{
name: 'min-size',
validate: (file) => {
if (file.size < 1024) {
return 'File must be at least 1KB';
}
return true;
}
}
]}
/>21. Drag to Reorder
Reorder files by dragging:
<FileUploader
onUpload={handleUpload}
enableReorder={true} // Enable reorder (default: false)
/>22. Custom Colors
Customize the color scheme:
<FileUploader
onUpload={handleUpload}
colors={{
primary: '#6366f1',
success: '#10b981',
error: '#ef4444',
warning: '#f59e0b',
info: '#3b82f6',
background: '#ffffff',
text: '#1f2937',
border: '#e5e7eb'
}}
/>23. PDF Preview
Full-screen PDF preview support:
<FileUploader
onUpload={handleUpload}
showImagePreview={true} // Also enables PDF preview
/>Click on PDF files to view in fullscreen modal.
🎯 Complete Example
import { FileUploader } from 'react-file-upload-kit';
import 'react-file-upload-kit/styles';
function App() {
const handleUpload = async (files: File[]) => {
const formData = new FormData();
files.forEach(file => formData.append('files', file));
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error('Upload failed');
}
const data = await response.json();
return data.files.map((file: any) => ({
name: file.name,
size: file.size,
type: file.type,
url: file.url
}));
};
return (
<FileUploader
onUpload={handleUpload}
multiple={true}
maxSizeMB={50}
maxFiles={20}
accept={['.pdf', '.doc', '.docx', '.jpg', '.png', '.gif']}
checkDuplicates={true}
allowRemove={true}
showFileIcons={true}
showImagePreview={true}
showToasts={true}
autoUpload={true}
enableBatchOperations={true}
enablePauseResume={true}
enableChunkedUpload={true}
enableCompression={true}
compressionQuality={0.8}
enableSearch={true}
enableViewToggle={true}
enableRename={true}
enableTags={true}
enableMetadata={true}
enableCopyUrl={true}
showUploadSpeed={true}
showETA={true}
maxConcurrentUploads={3}
theme="light"
colors={{
primary: '#0070f3',
success: '#10b981',
error: '#ef4444',
warning: '#f59e0b'
}}
onSuccess={(results) => {
console.log('Upload successful:', results);
}}
onError={(error) => {
console.error('Upload failed:', error);
}}
onValidationError={(errors) => {
console.warn('Validation errors:', errors);
}}
onFileRename={(file, newName) => {
console.log(`Renamed: ${file.name} -> ${newName}`);
}}
onMetadataUpdate={(file, metadata) => {
console.log('Metadata updated:', metadata);
}}
/>
);
}🔗 React Hook Form Integration
import { useForm } from 'react-hook-form';
import { FileUploadField } from 'react-file-upload-kit';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
documents: z.array(z.object({
name: z.string(),
size: z.number(),
type: z.string(),
url: z.string().optional()
})).min(1, 'At least one file is required')
});
function MyForm() {
const { control, handleSubmit } = useForm({
resolver: zodResolver(schema)
});
const handleUpload = async (files: File[]) => {
// Upload logic
return files.map(file => ({
name: file.name,
size: file.size,
type: file.type,
url: `https://example.com/uploads/${file.name}`
}));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<FileUploadField
name="documents"
control={control}
onUpload={handleUpload}
multiple={true}
maxSizeMB={10}
/>
<button type="submit">Submit</button>
</form>
);
}🧪 Testing
Unit Testing Example
import { render, screen, fireEvent } from '@testing-library/react';
import { FileUploader } from 'react-file-upload-kit';
test('renders file uploader', () => {
const handleUpload = jest.fn();
render(<FileUploader onUpload={handleUpload} />);
expect(screen.getByText(/drop files/i)).toBeInTheDocument();
});
test('handles file selection', async () => {
const handleUpload = jest.fn().mockResolvedValue([]);
const file = new File(['content'], 'test.jpg', { type: 'image/jpeg' });
render(<FileUploader onUpload={handleUpload} />);
const input = screen.getByRole('button');
fireEvent.click(input);
// Simulate file selection
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(fileInput, { target: { files: [file] } });
await waitFor(() => {
expect(handleUpload).toHaveBeenCalled();
});
});Integration Testing
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { FileUploader } from 'react-file-upload-kit';
test('complete upload flow', async () => {
const user = userEvent.setup();
const handleUpload = jest.fn().mockResolvedValue([
{ name: 'test.jpg', size: 1024, type: 'image/jpeg', url: 'https://example.com/test.jpg' }
]);
render(<FileUploader onUpload={handleUpload} />);
// Select file
const dropzone = screen.getByText(/drop files/i);
await user.click(dropzone);
// Wait for upload
await waitFor(() => {
expect(handleUpload).toHaveBeenCalled();
});
// Check success state
await waitFor(() => {
expect(screen.getByText(/successfully uploaded/i)).toBeInTheDocument();
});
});📖 API Reference
FileUploader Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onUpload | (files: File[]) => Promise<UploadResult[]> | required | Upload handler function |
| multiple | boolean | true | Allow multiple file selection |
| accept | string[] | undefined | Allowed file extensions |
| maxSizeMB | number | 10 | Maximum file size in MB |
| maxFiles | number | undefined | Maximum number of files |
| disabled | boolean | false | Disable the uploader |
| theme | "light" \| "dark" | "light" | Color theme |
| colors | ColorTheme | undefined | Custom color scheme |
| showToasts | boolean | true | Enable toast notifications |
| checkDuplicates | boolean | true | Check for duplicate files |
| allowRemove | boolean | true | Allow removing files |
| showFileIcons | boolean | true | Show file type icons |
| showImagePreview | boolean | true | Show image preview thumbnails |
| autoUpload | boolean | true | Auto-upload files when selected |
| enableBatchOperations | boolean | true | Enable batch operations |
| enablePauseResume | boolean | false | Enable pause/resume |
| enableChunkedUpload | boolean | false | Enable chunked upload |
| chunkSize | number | 1048576 | Chunk size in bytes (1MB) |
| enableReorder | boolean | false | Enable drag to reorder |
| enableRename | boolean | false | Enable file renaming |
| enableCompression | boolean | false | Enable image compression |
| compressionQuality | number | 0.8 | Compression quality (0-1) |
| compressionMaxSize | number | 1920 | Max width/height for compression |
| enableTags | boolean | false | Enable file tags |
| enableSearch | boolean | false | Enable search/filter |
| enableViewToggle | boolean | false | Enable grid/list toggle |
| defaultView | "grid" \| "list" | "list" | Default view mode |
| enableMetadata | boolean | false | Enable metadata editing |
| enableCopyUrl | boolean | false | Enable copy URL |
| enableDownloadPreview | boolean | false | Enable download preview |
| customValidations | CustomValidationRule[] | undefined | Custom validation rules |
| showUploadSpeed | boolean | false | Show upload speed |
| showETA | boolean | false | Show estimated time |
| maxConcurrentUploads | number | 3 | Max concurrent uploads |
| enableEncryption | boolean | false | Enable file encryption |
| encryptionKey | string | undefined | Encryption key |
| enableProgressPersistence | boolean | false | Enable progress persistence |
| wsProgress | WebSocketProgressOptions | undefined | WebSocket progress options |
| onSuccess | (results: UploadResult[]) => void | undefined | Success callback |
| onError | (error: unknown) => void | undefined | Error callback |
| onValidationError | (errors: string[]) => void | undefined | Validation error callback |
| onFileRename | (file: File, newName: string) => void | undefined | File rename callback |
| onMetadataUpdate | (file: File, metadata: FileMetadata) => void | undefined | Metadata update callback |
| renderFile | (file: File, meta: {...}) => ReactNode | undefined | Custom file row renderer |
UploadResult Interface
interface UploadResult {
name: string;
size: number;
type: string;
url?: string; // Optional URL returned by backend
}FileMetadata Interface
interface FileMetadata {
name?: string;
description?: string;
tags?: string[];
date?: Date;
custom?: Record<string, any>;
}🎨 Customization
Custom File Renderer
<FileUploader
onUpload={handleUpload}
renderFile={(file, meta) => (
<div className="custom-file-row">
<span>{file.name}</span>
{meta.progress !== undefined && (
<progress value={meta.progress} max={100} />
)}
{meta.onRemove && (
<button onClick={meta.onRemove}>Remove</button>
)}
</div>
)}
/>Custom Validation
<FileUploader
onUpload={handleUpload}
customValidations={[
{
name: 'custom-rule',
validate: (file) => {
// Return true if valid, or error message string
if (file.name.startsWith('test-')) {
return 'File name cannot start with "test-"';
}
return true;
}
}
]}
/>🔧 Advanced Usage
Chunked Upload with Progress
<FileUploader
onUpload={handleUpload}
enableChunkedUpload={true}
chunkSize={2 * 1024 * 1024} // 2MB chunks
onChunkedUpload={async (file, chunkIndex, chunk, totalChunks) => {
const formData = new FormData();
formData.append('file', file);
formData.append('chunk', chunk);
formData.append('chunkIndex', chunkIndex.toString());
formData.append('totalChunks', totalChunks.toString());
await fetch('/api/upload-chunk', {
method: 'POST',
body: formData
});
}}
/>WebSocket Progress
<FileUploader
onUpload={handleUpload}
wsProgress={{
wsUrl: 'wss://api.example.com/upload-progress',
onProgress: (fileId, progress) => {
console.log(`File ${fileId}: ${progress.percentage}%`);
}
}}
/>Progress Persistence
<FileUploader
onUpload={handleUpload}
enableProgressPersistence={true}
// Progress is automatically saved to localStorage
// and restored on page reload
/>🐛 Troubleshooting
CSS Not Loading
Make sure you import the CSS:
import 'react-file-upload-kit/styles';
// OR
import 'react-file-upload-kit/dist/index.css';Files Not Uploading
Check that your onUpload function returns the correct format:
const handleUpload = async (files: File[]) => {
// Your upload logic
return files.map(file => ({
name: file.name,
size: file.size,
type: file.type,
url: 'https://example.com/uploads/' + file.name
}));
};TypeScript Errors
Make sure you have TypeScript 5.0+ and React 17+:
{
"devDependencies": {
"typescript": "^5.0.0",
"@types/react": "^18.0.0"
}
}📝 License
MIT License - see LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📧 Support
For issues, questions, or feature requests, please open an issue on GitHub.
🎉 Thank You
Thank you for using react-file-upload-kit! If you find it helpful, please consider giving it a ⭐ on GitHub.
