Skip to content
Devix Open Source

Guide

Moving from Dropzone or FilePond

From Dropzone

// before
new Dropzone('#drop', {
  url: '/upload',
  maxFilesize: 5,             // megabytes, despite the docs
  acceptedFiles: 'image/*,.pdf',
  maxFiles: 10,
  parallelUploads: 3,
  paramName: 'file',
});

// after
import { createFileUploader } from '@devix-labs/file-uploader';
import '@devix-labs/file-uploader/styles.css';

createFileUploader(document.querySelector('#docs'), {
  url: '/upload',
  maxSize: '5MB',
  accept: 'image/*,.pdf',
  maxFiles: 10,
  concurrency: 3,
});
Dropzone Here
maxFilesize: 5 (megabytes) maxSize: '5MB' — or 5_000_000, which is bytes and says so
acceptedFiles accept, matched on the extension as well as the type
parallelUploads concurrency
paramName fieldName
headers, params headers, data — and both may be functions, so a token stays fresh
autoProcessQueue: false autoUpload: false, then uploader.upload()
chunking, chunkSize, retryChunks chunkSize, plus resume, which Dropzone has no equivalent of
.on('success' | 'error' | 'queuecomplete') onSuccess, onError, onComplete, or the dx:upload* events
.removeFile(file) uploader.remove(file.id)
Attaches to a <div class="dropzone"> Attaches to a real <input type="file">, which keeps the form working
dictFileTooBig and thirty other dict* strings one strings object, and problem(code, limit, actual) for every refusal

Dropzone's top four open issues are all reports of the same confusion over maxFilesize; that is the one thing this package will not let you get wrong.

From FilePond

// before
FilePond.create(input, {
  server: '/upload',
  maxFileSize: '5MB',
  acceptedFileTypes: ['image/*'],
  maxFiles: 10,
  allowMultiple: true,
});

// after
createFileUploader(input, {
  url: '/upload',
  maxSize: '5MB',
  accept: 'image/*',
  maxFiles: 10,
});
FilePond Here
server as an object of process/revert/load/restore url, method, headers, data — one request, the one your server already handles
maxFileSize, acceptedFileTypes maxSize, accept
allowMultiple maxFiles, and the input's own multiple
allowImagePreview thumbnails
labelIdle and the other label* options one strings object
filepond--* classes dxu-* classes, plus classNames for your own
plugins for size, type, preview all in the 8.9 kB
— RTL, asked for in 2019
— speed and time remaining, asked for since
— upload order, asked for since

FilePond is 34.1 kB of JavaScript plus 3.4 kB of CSS, measured from its own published build.

From react-dropzone

react-dropzone is a hook: it gives you the files and stops there — no list, no progress, no uploading. If that is all you needed, it is 9.5 million downloads a week of exactly the right thing. If you then wrote the upload, the list, the progress bar and the retry logic yourself, this is that part:

// before
const { getRootProps, getInputProps } = useDropzone({ onDrop, accept: { 'image/*': [] }, maxSize: 5e6 });
// …and then your own list, your own XHR, your own progress state

// after
import { FileUploader } from '@devix-labs/file-uploader/react';
<FileUploader url="/upload" accept="image/*" maxSize="5MB" onComplete={done} />

From Uppy

Uppy is a platform: remote sources, S3 multipart, a companion server, an image editor. If you use those, stay. If you installed nine packages to put files on your own server with a progress bar, this is that, in one with no dependencies — and its icons are options rather than a three-year-old request.

From a plain <input type="file">

createFileUploader(document.querySelector('#docs'));

With no url, nothing about your form changes: the same input, the same name, the same $_FILES. You gain a drop zone, a list, previews, and the size and type rules enforced before anything is sent — and the page still works if the JavaScript does not.

Updated 15 Sep 2026