File Upload Component
The FileUpload component provides a beautiful drag-and-drop interface for uploading files with built-in validation, progress tracking, and preview.
Basic Usage
import { FileUpload } from '@dropper/react'
function App() {
return (
<FileUpload
onSuccess={(file) => console.log('Uploaded:', file.url)}
onError={(error) => console.error('Upload failed:', error)}
/>
)
}
Props
interface FileUploadProps {
folderId?: string
accept?: string
maxSize?: number
maxFiles?: number
multiple?: boolean
disabled?: boolean
showPreview?: boolean
showProgress?: boolean
className?: string
metadata?: Record<string, unknown>
onSuccess?: (file: FileResponseDto) => void
onError?: (error: Error, file: File) => void
onProgress?: (progress: number, file: File) => void
onValidationError?: (errors: ValidationError[]) => void
onFilesSelected?: (files: File[]) => void
}
folderId
Upload files to a specific folder:
<FileUpload
folderId="folder_abc123"
onSuccess={(file) => console.log('Uploaded to folder')}
/>
accept
Restrict file types using MIME types or extensions:
{/* Images only */}
<FileUpload accept="image/*" />
{/* Specific types */}
<FileUpload accept="image/jpeg,image/png,image/gif" />
{/* Multiple formats */}
<FileUpload accept="image/*,.pdf,.doc,.docx" />
maxSize
Set maximum file size in bytes:
{/* 5MB limit */}
<FileUpload maxSize={5 * 1024 * 1024} />
{/* 10MB limit (default) */}
<FileUpload maxSize={10 * 1024 * 1024} />
maxFiles
Limit the number of files:
{/* Single file */}
<FileUpload maxFiles={1} multiple={false} />
{/* Up to 10 files (default) */}
<FileUpload maxFiles={10} />
{/* Unlimited */}
<FileUpload maxFiles={Infinity} />
multiple
Enable multiple file selection:
{/* Multiple files (default) */}
<FileUpload multiple />
{/* Single file only */}
<FileUpload multiple={false} maxFiles={1} />
disabled
Disable the upload component:
const [uploading, setUploading] = useState(false)
<FileUpload
disabled={uploading}
onSuccess={() => setUploading(false)}
/>
showPreview
Show file previews after selection:
{/* Show previews (default) */}
<FileUpload showPreview />
{/* Hide previews */}
<FileUpload showPreview={false} />
showProgress
Display upload progress:
{/* Show progress (default) */}
<FileUpload showProgress />
{/* Hide progress */}
<FileUpload showProgress={false} />
metadata
Attach custom metadata to uploaded files:
<FileUpload
metadata={{
userId: '123',
category: 'profile-pictures',
tags: ['avatar', 'user'],
}}
/>
Event Handlers
onSuccess
Called when a file uploads successfully:
<FileUpload
onSuccess={(file) => {
console.log('File uploaded!')
console.log('URL:', file.url)
console.log('ID:', file.id)
console.log('Size:', file.size)
}}
/>
onError
Called when upload fails:
<FileUpload
onError={(error, file) => {
console.error(`Failed to upload ${file.name}:`, error.message)
showNotification(`Upload failed: ${error.message}`)
}}
/>
onProgress
Track upload progress:
<FileUpload
onProgress={(progress, file) => {
console.log(`${file.name}: ${progress}%`)
updateProgressBar(file.name, progress)
}}
/>
onValidationError
Handle validation errors:
<FileUpload
onValidationError={(errors) => {
errors.forEach((error) => {
console.error(`${error.file.name}: ${error.message}`)
})
}}
/>
onFilesSelected
Called when files are selected (before upload):
<FileUpload
onFilesSelected={(files) => {
console.log(`Selected ${files.length} files`)
// Files won't upload automatically when this is provided
// You control when to upload
}}
/>
Complete Examples
Image Upload
import { FileUpload } from '@dropper/react'
import { useState } from 'react'
function ImageUpload() {
const [uploadedImages, setUploadedImages] = useState([])
return (
<div>
<FileUpload
accept="image/*"
maxSize={5 * 1024 * 1024} // 5MB
maxFiles={10}
multiple
showPreview
onSuccess={(file) => {
setUploadedImages((prev) => [...prev, file])
console.log('Image uploaded:', file.url)
}}
onError={(error, file) => {
console.error(`Failed to upload ${file.name}:`, error)
}}
/>
<div className="grid grid-cols-3 gap-4 mt-4">
{uploadedImages.map((image) => (
<img
key={image.id}
src={image.url}
alt={image.originalFilename}
className="w-full h-32 object-cover rounded"
/>
))}
</div>
</div>
)
}
Document Upload
import { FileUpload } from '@dropper/react'
function DocumentUpload() {
return (
<FileUpload
accept=".pdf,.doc,.docx,.txt"
maxSize={10 * 1024 * 1024} // 10MB
maxFiles={5}
folderId="folder_documents"
metadata={{
category: 'documents',
uploadedBy: 'user_123',
}}
onSuccess={(file) => {
console.log('Document uploaded:', file.originalFilename)
}}
onValidationError={(errors) => {
errors.forEach((error) => {
alert(`${error.file.name}: ${error.message}`)
})
}}
/>
)
}
Profile Picture Upload
import { FileUpload } from '@dropper/react'
import { useState } from 'react'
function ProfilePictureUpload() {
const [profilePicture, setProfilePicture] = useState(null)
const [uploading, setUploading] = useState(false)
return (
<div>
{profilePicture && (
<img
src={profilePicture.url}
alt="Profile"
className="w-32 h-32 rounded-full object-cover mb-4"
/>
)}
<FileUpload
accept="image/jpeg,image/png"
maxSize={2 * 1024 * 1024} // 2MB
maxFiles={1}
multiple={false}
disabled={uploading}
metadata={{ type: 'profile-picture' }}
onSuccess={(file) => {
setProfilePicture(file)
setUploading(false)
}}
onError={(error) => {
console.error('Upload failed:', error)
setUploading(false)
}}
onProgress={(progress) => {
setUploading(true)
console.log(`Upload progress: ${progress}%`)
}}
/>
</div>
)
}
Upload with Confirmation
import { FileUpload } from '@dropper/react'
import { useState } from 'react'
function UploadWithConfirmation() {
const [selectedFiles, setSelectedFiles] = useState([])
const [uploading, setUploading] = useState(false)
const handleUpload = async () => {
setUploading(true)
// Handle upload manually
// This example shows the pattern, actual implementation
// would use the client directly
}
return (
<div>
<FileUpload
onFilesSelected={(files) => {
setSelectedFiles(files)
// Files won't upload automatically
}}
/>
{selectedFiles.length > 0 && (
<div className="mt-4">
<p>Selected {selectedFiles.length} files</p>
<button
onClick={handleUpload}
disabled={uploading}
className="btn-primary"
>
{uploading ? 'Uploading...' : 'Confirm Upload'}
</button>
</div>
)}
</div>
)
}
Upload to Folder
import { FileUpload } from '@dropper/react'
import { useState } from 'react'
function FolderUpload() {
const [currentFolder, setCurrentFolder] = useState('folder_123')
return (
<div>
<select
value={currentFolder}
onChange={(e) => setCurrentFolder(e.target.value)}
>
<option value="folder_123">Documents</option>
<option value="folder_456">Images</option>
<option value="folder_789">Videos</option>
</select>
<FileUpload
folderId={currentFolder}
onSuccess={(file) => {
console.log(`Uploaded to ${currentFolder}:`, file.url)
}}
/>
</div>
)
}
Styling
Custom Class Name
<FileUpload
className="my-custom-upload"
onSuccess={(file) => console.log('Uploaded:', file)}
/>
Themed Upload
The component automatically uses the theme from DropperProvider:
<DropperProvider
publishableKey="pk_dropper_test_xxx"
theme={{ primary: '#10b981' }}
>
<FileUpload /> {/* Uses green theme */}
</DropperProvider>
Validation
The component includes built-in validation:
File Type Validation
<FileUpload
accept="image/*"
onValidationError={(errors) => {
// Error: "File type not allowed"
}}
/>
File Size Validation
<FileUpload
maxSize={5 * 1024 * 1024}
onValidationError={(errors) => {
// Error: "File size exceeds 5 MB"
}}
/>
File Count Validation
<FileUpload
maxFiles={10}
onValidationError={(errors) => {
// Error: "Maximum 10 files allowed"
}}
/>
Features
Drag and Drop
- Drag files over the component to upload
- Visual feedback when dragging
- Drop files to start upload
File Previews
- Image previews with thumbnails
- File icons for documents
- File size and name display
- Remove files before upload
Progress Tracking
- Individual file progress bars
- Overall upload progress
- Upload status indicators
- Success/error states
Validation
- File type validation
- File size validation
- File count validation
- Custom validation rules
Accessibility
The component is fully accessible:
- Keyboard navigation support
- Screen reader friendly
- ARIA labels and roles
- Focus management
Best Practices
1. Set Appropriate Limits
{/* Images: 5-10MB */}
<FileUpload accept="image/*" maxSize={5 * 1024 * 1024} />
{/* Videos: 50-100MB */}
<FileUpload accept="video/*" maxSize={100 * 1024 * 1024} />
{/* Documents: 10-20MB */}
<FileUpload accept=".pdf,.doc" maxSize={10 * 1024 * 1024} />
2. Provide Feedback
<FileUpload
onSuccess={(file) => {
showNotification('File uploaded successfully!')
}}
onError={(error) => {
showNotification(`Upload failed: ${error.message}`, 'error')
}}
/>
3. Handle Errors Gracefully
<FileUpload
onError={(error, file) => {
if (error.message.includes('size')) {
alert('File is too large')
} else if (error.message.includes('type')) {
alert('File type not supported')
} else {
alert('Upload failed. Please try again.')
}
}}
/>
4. Use Metadata
<FileUpload
metadata={{
userId: currentUser.id,
timestamp: new Date().toISOString(),
source: 'web-app',
}}
/>
TypeScript Support
The component is fully typed:
import type { FileUploadProps, FileResponseDto } from '@dropper/react'
const props: FileUploadProps = {
accept: 'image/*',
maxSize: 5 * 1024 * 1024,
onSuccess: (file: FileResponseDto) => {
console.log(file.url)
},
}
<FileUpload {...props} />
Next Steps
- File List Component - Display uploaded files
- Folder Browser - Organize files in folders
- useDropper Hook - Access Dropper client