npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-file-upload-kit

v1.0.5

Published

A customizable React file upload kit with drag & drop, validation, and progress.

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.

Version License TypeScript


✨ 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-form

Peer Dependencies

  • react >= 17.0.0
  • react-dom >= 17.0.0
  • react-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.