Skip to main content

Frequently Asked Questions

Common questions and answers about Dropup.

General

What is Dropup?

Dropup is a lightweight, headless React library for file uploads. It provides drag-and-drop functionality, file validation, upload progress tracking, and support for cloud storage - all in a package under 10KB gzipped.

Why "headless"?

Headless means Dropup doesn't include any UI components. It provides the logic and state management, while you build the UI however you want. This gives you complete control over the look and feel.

What's the bundle size?

  • Core (@samithahansaka/dropup): < 10KB gzipped
  • With cloud support: +2KB per provider
  • With image processing: +5KB
  • With tus protocol: +3KB (requires tus-js-client peer)

Does it support TypeScript?

Yes! Dropup is written in TypeScript and includes comprehensive type definitions. No @types package needed.

What React version is required?

React 16.8+ (requires hooks support).

Usage

How do I upload files?

const { files, actions } = useDropup({
upload: { url: '/api/upload' },
});

// Upload all files
actions.upload();

// Upload specific files
actions.upload(['file-id-1', 'file-id-2']);

How do I handle validation errors?

useDropup({
accept: 'image/*',
maxSize: 5 * 1024 * 1024,

onValidationError: (errors) => {
errors.forEach(({ file, errors }) => {
console.log(`${file.name}: ${errors.join(', ')}`);
});
},
});

Can I use custom upload logic?

Yes! Pass a function instead of config object:

useDropup({
upload: async (file, options) => {
const { signal, onProgress } = options;

// Your custom upload logic
const response = await customUpload(file.file, {
signal,
onProgress,
});

return { url: response.url };
},
});

How do I add files programmatically?

const { actions } = useDropup();

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

Can I have multiple drop zones?

Yes! Each useDropup call creates an independent instance:

const images = useDropup({ accept: 'image/*' });
const documents = useDropup({ accept: '.pdf' });

// Use separately
<div {...images.getDropProps()}>...</div>
<div {...documents.getDropProps()}>...</div>

Uploads

How do I show upload progress?

const { files } = useDropup({ upload: { url: '/api/upload' } });

{files.map(file => (
<div key={file.id}>
{file.name}: {file.progress}%
</div>
))}

How do I cancel an upload?

const { actions } = useDropup();

// Cancel specific file
actions.cancel('file-id');

// Cancel all uploads
actions.cancel();

How do I retry failed uploads?

const { actions } = useDropup();

// Retry specific files
actions.retry(['file-id']);

// Retry all failed
actions.retry();

Does it support chunked uploads?

Yes! Use createChunkedUploader:

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

useDropup({
upload: createChunkedUploader({
url: '/api/upload/chunk',
chunkSize: 5 * 1024 * 1024, // 5MB
}),
});

Can I upload to S3 directly?

Yes! Use the cloud uploader:

import { createS3Uploader } from '@samithahansaka/dropup/cloud/s3';

useDropup({
upload: createS3Uploader({
getPresignedUrl: async (file) => {
const res = await fetch('/api/s3/presign', {
method: 'POST',
body: JSON.stringify({ filename: file.name }),
});
return res.json();
},
}),
});

Validation

How do I restrict file types?

// By MIME type
useDropup({ accept: 'image/*' });

// By extension
useDropup({ accept: '.pdf, .doc' });

// Multiple
useDropup({ accept: ['image/*', 'application/pdf'] });

How do I set size limits?

useDropup({
maxSize: 10 * 1024 * 1024, // 10MB max
minSize: 1024, // 1KB min
});

How do I limit number of files?

useDropup({
maxFiles: 5,
});

Can I add custom validation?

Yes! Use customRules:

useDropup({
customRules: [
(file) => {
if (file.name.includes('draft')) {
return 'Draft files not allowed';
}
return true;
},
],
});

Previews

How do I show image previews?

Previews are enabled by default:

const { files } = useDropup();

{files.map(file => (
file.preview && <img src={file.preview} alt="" />
))}

Do I need to clean up preview URLs?

No! Dropup automatically revokes Object URLs when files are removed or the component unmounts.

Can I disable previews?

useDropup({ generatePreviews: false });

Troubleshooting

Files aren't uploading

  1. Check that upload is configured:

    useDropup({ upload: { url: '/api/upload' } });
  2. Make sure you call actions.upload() (unless autoUpload: true)

  3. Check browser console for network errors

Preview URLs not working

  1. Ensure the file is an image
  2. Check that generatePreviews isn't false
  3. Verify the file object has a valid preview property

Drag and drop not working

  1. Make sure you spread getDropProps() on a container element
  2. Include the hidden input: <input {...getInputProps()} />
  3. Check that disabled isn't true

TypeScript errors

  1. Update to the latest Dropup version
  2. Ensure tsconfig.json has proper moduleResolution
  3. Check that @samithahansaka/dropup is in dependencies, not devDependencies

Memory leaks

  1. Ensure components using useDropup unmount properly
  2. Call actions.reset() before unmounting if needed
  3. Don't store files in external state without cleanup

Compatibility

Does it work with Next.js?

Yes! Use the 'use client' directive:

'use client';
import { useDropup } from '@samithahansaka/dropup';

Does it work with React Native?

Yes! Use the native adapter:

import { NativeAdapter } from '@samithahansaka/dropup/native';

useDropup({ adapter: NativeAdapter });

Does it support SSR?

Yes! Dropup is SSR-safe. It only uses browser APIs when they're available.

Browser support?

All modern browsers:

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+

Contributing

How can I contribute?

  1. Fork the repository
  2. Create a feature branch
  3. Submit a pull request

See CONTRIBUTING.md for details.

How do I report bugs?

Open an issue at github.com/samithahansaka/dropup/issues.

Is there a roadmap?

Check the GitHub issues and discussions for planned features.