Works with any backend npm install Zero dependencies

Svelte 4 + Svelte 5 via multipleupload/svelte

A minimal factory wrapper exposed at multipleupload/svelte. Returns an imperative handle ({ instance, update, destroy }) that mounts to any host element, forwards every core event as a same-named on* callback, and tears down on unmount. Works with both Svelte 4 stores and Svelte 5 runes - nothing in the wrapper is version-specific.

Subpath import: multipleupload/svelte ships in the same npm package - no separate install. Svelte declared as an optional peer dep so non-Svelte consumers don't pull anything.
Install
npm install multipleupload svelte
Svelte 5 (runes)
<script>
 import { onMount, onDestroy } from 'svelte';
 import { createUploader } from 'multipleupload/svelte';
 import 'multipleupload/multipleupload.css';

 let host = $state();
 let uploader;
 let progress = $state(0);

 onMount(() => {
 uploader = createUploader(host, {
 options: {
 uploadUrl: '/api/upload',
 multiple: true,
 autoUpload: false,
 strategy: 'chunked',
 chunkSize: 5 * 1024 * 1024,
 chunkConcurrency: 4
 },
 onProgress: (o) => { progress = o.progress; },
 onTaskComplete: (task, result) => {
 console.log('uploaded', result.fileGuid, result.fileName);
 },
 onError: (err) => console.error(err)
 });
 });

 onDestroy(() => uploader?.destroy());

 function startUpload() { uploader.instance.upload(); }
</script>

<div bind:this={host}></div>
<button onclick={startUpload}>Start upload</button>
<p>Overall: {progress}%</p>
Svelte 4 (stores)
<script>
 import { onMount, onDestroy } from 'svelte';
 import { writable } from 'svelte/store';
 import { createUploader } from 'multipleupload/svelte';
 import 'multipleupload/multipleupload.css';

 let host;
 let uploader;
 const progress = writable(0);

 onMount(() => {
 uploader = createUploader(host, {
 options: { uploadUrl: '/api/upload', multiple: true },
 onProgress: (o) => progress.set(o.progress),
 onTaskComplete: (task, result) => console.log('done', result)
 });
 });
 onDestroy(() => uploader?.destroy());
</script>

<div bind:this={host}></div>
<p>Overall: {$progress}%</p>
Forwarded events (same-named on* callbacks)
onTaskAdded, onTaskRemoved, onTaskStarted, onTaskProgress, onTaskComplete,
onTaskFailed, onTaskCancelled, onTaskPaused, onTaskResumed,
onQueueComplete, onAllComplete, onProgress, onStateRestored, onError
Imperative access via the handle
// uploader.instance is the full MultipleUpload object
uploader.instance.upload();
uploader.instance.pauseAll();
uploader.instance.openImageEditor(file);
uploader.instance.openWebcamCapture();
uploader.instance.setLocale('fr');

// uploader.update() swaps event handlers without rebuilding
uploader.update({ onProgress: newHandler });
Why a factory, not a .svelte SFC?
  • Ships pre-compiled JS - no Svelte compiler step needed at consumer build time.
  • Same wrapper works across Svelte 4 and Svelte 5 (stores vs runes are framework-only concerns; the wrapper is plain JS).
  • SvelteKit's hydration model is unbothered - the wrapper only touches DOM after onMount.