Skip to main content

File Handling

Dropup provides a seamless experience for handling files from the moment they're selected until they're uploaded.

File Selection Methods

Drag and Drop

Use getDropProps() to enable drag-and-drop on any element:

function DropZone() {
const { getDropProps, getInputProps, state } = useDropup();

return (
<div
{...getDropProps()}
style={{
border: state.isDragging ? '2px dashed blue' : '2px dashed gray',
backgroundColor: state.isDragging ? '#f0f8ff' : 'transparent',
}}
>
<input {...getInputProps()} />
<p>Drop files here</p>
</div>
);
}

Click to Select

The drop zone is also clickable by default:

<div {...getDropProps()}>
<input {...getInputProps()} />
<p>Click or drag files here</p>
</div>

Programmatic Selection

Open the file dialog programmatically:

const { openFileDialog } = useDropup();

<button onClick={openFileDialog}>
Select Files
</button>

Programmatic File Addition

Add files directly (useful for paste events or integrations):

const { actions } = useDropup();

// From clipboard
document.addEventListener('paste', (e) => {
const files = e.clipboardData?.files;
if (files?.length) {
actions.addFiles(files);
}
});

File Object Structure

Each file in the files array has this structure:

interface DropupFile {
// Identification
id: string; // Unique identifier (auto-generated)
file: File; // Original browser File object

// Metadata
name: string; // File name
size: number; // Size in bytes
type: string; // MIME type (e.g., "image/png")

// Preview (for images)
preview?: string; // Object URL for preview

// Upload State
status: FileStatus; // 'idle' | 'uploading' | 'complete' | 'error' | 'paused'
progress: number; // 0-100

// Results
uploadedUrl?: string; // URL after successful upload
response?: unknown; // Server response
error?: DropupError; // Error details if failed

// Custom data
meta?: Record<string, unknown>;
}

File Status Lifecycle

idle → uploading → complete
↘ error → (retry) → uploading
↘ paused → (resume) → uploading

Status Values

StatusDescription
idleFile added but not yet uploading
uploadingCurrently uploading
completeUpload successful
errorUpload failed
pausedUpload paused (for resumable uploads)

Working with Files

Accessing Files

const { files } = useDropup();

// All files
console.log(files);

// Filter by status
const uploading = files.filter(f => f.status === 'uploading');
const completed = files.filter(f => f.status === 'complete');
const failed = files.filter(f => f.status === 'error');

Removing Files

const { files, actions } = useDropup();

// Remove single file
actions.remove(files[0].id);

// Remove all files
actions.reset();

Updating File Metadata

const { actions } = useDropup();

// Add custom metadata
actions.updateFileMeta(fileId, {
customField: 'value',
category: 'documents',
});

File Previews

For image files, Dropup can generate preview URLs:

const { files } = useDropup({
generatePreviews: true, // default: true
});

// Use preview in your UI
{files.map(file => (
file.preview && (
<img
src={file.preview}
alt={file.name}
style={{ maxWidth: 100, maxHeight: 100 }}
/>
)
))}
Memory Management

Preview URLs are Object URLs that consume memory. Dropup automatically revokes them when files are removed or the component unmounts.

File Size Formatting

Helper to display file sizes:

function formatFileSize(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

// Usage
{files.map(file => (
<span>{formatFileSize(file.size)}</span>
))}

Handling Large Files

For large files, consider chunked uploads:

import { useDropup, createChunkedUploader } from '@samithahansaka/dropup';

const { files } = useDropup({
upload: createChunkedUploader({
url: '/api/upload',
chunkSize: 5 * 1024 * 1024, // 5MB chunks
}),
});

See Chunked Uploads for more details.