Works with any backend npm install Zero dependencies

Kitchen Sink (Everything)

Every major feature combined in one demo: chunked, validated, image-processed, hashed, persistent, with full event logging.

Files0
Speed-
Progress0%
Completed0
(function() {
 var logEl = document.getElementById('log');
 function log(m) { var d = document.createElement('div'); d.className='pkg-log-entry'; d.textContent=new Date().toLocaleTimeString()+' '+m; logEl.appendChild(d); logEl.scrollTop=logEl.scrollHeight; }
 document.getElementById('clear-log').addEventListener('click', function() { logEl.innerHTML=''; });

 var u = new MultipleUpload('#demo', {
 uploadUrl: '/api/upload',
 multiple: true,
 autoUpload: false,
 chunked: true,
 chunkSize: '1MB',
 chunkConcurrency: 2,
 concurrency: 2,
 retries: 2,
 retryBackoff: 'exponential',
 maxFileSize: '50MB',
 allowedExtensions: '.jpg,.jpeg,.png,.gif,.webp,.pdf,.doc,.docx,.xls,.xlsx,.zip,.mp4,.txt',
 preventDuplicates: true,
 showThumbnails: true,
 removable: true,
 confirmRemove: true,
 paste: true,
 fullPageDrop: true,
 autoOrient: true,
 imageResize: { maxWidth: 1920, maxHeight: 1920, quality: 0.9 },
 watermark: { text: 'DEMO', fontSize: 24, position: 'bottom-right', color: 'rgba(0,0,0,0.15)' },
 computeHash: true,
 hashAlgorithm: 'sha256',
 persistState: true,
 persistKey: 'kitchen-sink-demo',
 onFileAdded: function(t) { log('+ ' + t.fileName); document.getElementById('ks-files').textContent = u.tasks.length; },
 onTaskProgress: function(t) {
 document.getElementById('ks-speed').textContent = MultipleUpload.formatSize(t.speed) + '/s';
 document.getElementById('ks-pct').textContent = t.progress + '%';
 },
 onTaskComplete: function(t) { log('Done: ' + t.fileName); document.getElementById('ks-done').textContent = u.getCompletedFiles().length; },
 onTaskError: function(t,e) { log('ERR: ' + t.fileName + ' ' + e); },
 onChunkComplete: function(f,i,n) { log('Chunk ' + (i+1) + '/' + n + ' ' + f.name); },
 onQueueComplete: function(f) { log('=== ALL DONE: ' + f.length + ' files ==='); },
 onHashComputed: function(t,h) { log('Hash: ' + t.fileName + ' ' + h.slice(0,16) + '...'); },
 onValidationError: function(m,n) { log('INVALID: ' + (n||'') + ' ' + m); }
 });
 document.getElementById('btn-upload').onclick = function() { u.upload(); };
 document.getElementById('btn-pause').onclick = function() { u.pause(); };
 document.getElementById('btn-resume').onclick = function() { u.resume(); };
 document.getElementById('btn-cancel').onclick = function() { u.cancel(); };
 document.getElementById('btn-reset').onclick = function() { u.reset(); };
})();

Event Log