React, Vue & Angular
The Tag Helper is a convenience wrapper: everything it renders can be created with CoreUpload.create(element, options). That is the whole integration story for a SPA — plus knowing when to destroy the instance.
First-party adapters ship in the package: the NuGet package includes useUploader() for React and Vue, a Svelte action and an Angular service under _content/CoreUpload/adapters/<framework>/ (with TypeScript definitions). They resolve the loaded window.CoreUpload global automatically. The patterns below use the plain JS API, which the adapters wrap.
React
function Uploader() {
const host = useRef(null);
const [status, setStatus] = useState('');
useEffect(() => {
const u = CoreUpload.create(host.current, {
uploadUrl: '/api/upload/upload',
chunked: true,
persistState: true
});
u.on('taskProgress', t => setStatus(`${t.fileName}: ${t.progress}%`));
u.on('taskComplete', (t, r) => setStatus(`${t.fileName} → ${r.fileGuid}`));
return () => u.destroy(); // strict-mode double-mount safe
}, []);
return <><div ref={host} /><p>{status}</p></>;
} Vue 3
<script setup>
const host = ref(null);
let uploader;
onMounted(() => {
uploader = CoreUpload.create(host.value, { uploadUrl: '/api/upload/upload', chunked: true });
});
onBeforeUnmount(() => uploader?.destroy());
</script>
<template><div ref="host"></div></template> Angular
@Component({ selector: 'app-uploader', template: '<div #host></div>' })
export class UploaderComponent implements AfterViewInit, OnDestroy {
@ViewChild('host') host!: ElementRef;
private uploader: any;
ngAfterViewInit() {
this.uploader = (window as any).CoreUpload.create(this.host.nativeElement, {
uploadUrl: '/api/upload/upload', chunked: true
});
}
ngOnDestroy() { this.uploader?.destroy(); }
} The three rules that matter
- Create once per mount, destroy on unmount.
destroy()removes listeners, timers and cross-tab plumbing — skipping it leaks all three under hot-reload. - Send auth with the request, not the constructor. The
headersoption accepts a function evaluated per request, so short-lived JWTs stay fresh:headers: () => ({ Authorization: 'Bearer ' + getToken() }). - Cross-origin APIs need CORS on the API, and for direct-to-cloud also on the bucket — see the direct-to-cloud guide.