Works with any backend npm install Zero dependencies

Angular 17+ standalone component via multipleupload/angular

A standalone Angular component (<multiple-upload>) that can be imported directly into any standalone-compatible Angular module or component. Late-binds @angular/core via lazy evaluation so non-Angular consumers don't pay the peer-dep tax. Works with Angular 17, 18, 19, 20.

Subpath import: multipleupload/angular ships in the same npm package. @angular/core is an optional peer dep - only resolved when you actually use the component class.
Install
npm install multipleupload @angular/core
Standalone component usage
// app.component.ts
import { Component } from '@angular/core';
import { MultipleUploadComponent } from 'multipleupload/angular';
import 'multipleupload/multipleupload.css';

@Component({
 selector: 'app-root',
 standalone: true,
 imports: [MultipleUploadComponent],
 template: `
 <multiple-upload
 [options]="uploadOptions"
 (taskComplete)="onComplete($event)"
 (taskProgress)="onProgress($event)"
 (uploadError)="onError($event)">
 </multiple-upload>
 `
})
export class AppComponent {
 uploadOptions = {
 uploadUrl: '/api/upload',
 multiple: true,
 autoUpload: false,
 strategy: 'chunked',
 chunkSize: 5 * 1024 * 1024,
 chunkConcurrency: 4
 };

 onComplete([task, result]: any) {
 console.log('uploaded', result.fileGuid, result.fileName);
 }
 onProgress(task: any) {
 console.log(task.fileName, task.progress + '%');
 }
 onError(err: any) {
 console.error(err);
 }
}
Emitted events

Every core event is a same-named @Output(). Multi-arg events (taskComplete, taskFailed) emit as a tuple [task, result].

taskAdded, taskRemoved, taskStarted, taskProgress, taskComplete,
taskFailed, taskCancelled, taskPaused, taskResumed,
queueComplete, allComplete, progress, stateRestored,
uploadError // 'error' is renamed to avoid DOM ErrorEvent collision
Use without the component (services, tests, manual bootstrap)
import { attachUploader } from 'multipleupload/angular';

// In an Angular service or anywhere outside a component context:
const handle = attachUploader(hostEl, { uploadUrl: '/api/upload' }, {
 taskComplete: (task, result) => console.log(result),
 error: (err) => console.error(err)
});

// Tear down later:
handle.destroy();
Imperative API (via @ViewChild + a host ref)
// Wrap in a small directive if you need imperative access from the parent.
// The component itself doesn't expose ViewChild on the underlying instance,
// but a thin pattern works:

@Component({
 template: `<div #host></div><button (click)="upload()">Upload</button>`
})
export class ManualUploaderComponent implements AfterViewInit, OnDestroy {
 @ViewChild('host') hostRef!: ElementRef;
 private handle: any;

 ngAfterViewInit() {
 this.handle = attachUploader(this.hostRef.nativeElement, {
 uploadUrl: '/api/upload', autoUpload: false
 });
 }
 upload() { this.handle.instance.upload(); }
 ngOnDestroy() { this.handle?.destroy(); }
}
Why lazy @angular/core binding?
  • The wrapper module itself require()s nothing from @angular/core at load time.
  • The MultipleUploadComponent getter calls require('@angular/core') lazily on first access.
  • Non-Angular consumers (React, Vue, Svelte, plain JS) can keep importing multipleupload/angular's attachUploader without dragging in 100 KB of Angular runtime.