Skip to content

Uploader ​

Queue, progress, cancel — XHR or your own

Files that upload on their own, with progress, before the form is sent — attachments, a photo set, a batch import. When the files should simply go with the form on submit, use FileInput.

Basic
  • With url it POSTs each file (as field, with headers) and tracks progress. Without it, handle @upload yourself: call progress(n), then done() or fail(message).
  • auto starts as soon as files are picked; otherwise the Upload button does. maxSize rejects large files before they're sent.
  • Finished and failed uploads are announced; each row's button names its file. Leaving the page, or unmounting, stops uploads in progress.

Usage ​

ts
import { BlessUploader } from "blessing-ui";

API ​

Props

NameTypeDefaultDescription
urlstring—POST target; omit to handle uploads yourself via the `upload` event
fieldstring"file"form field name
headersRecord<string, string>—
acceptstring—
multiplebooleantrue
autobooleanfalsestart as soon as files are picked
maxSizenumber—
labelstring"Drop files here or click to browse"
hintstring—

Events

NamePayloadDescription
done[item: BlessUpload]
error[item: BlessUpload]
upload[item: BlessUpload, progress: (n: number) => void, done: () => void, fail: (msg?: string | undefined) => void]

Slots

NameScopeDescription
actions{ start: () => void; clear: () => { id: number; file: { readonly lastModified: number; readonly name: string; readonly webkitRelativePath: string; readonly size: number; readonly type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start?: number | undefined, end?: number | undefined, contentType?: string | undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }; progress: number; status: "done" | "uploading" | "error" | "queued" | "cancelled"; error?: string | undefined; xhr?: { onreadystatechange: ((this: XMLHttpRequest, ev: Event) => any) | null; readonly readyState: number; readonly response: any; readonly responseText: string; responseType: XMLHttpRequestResponseType; readonly responseURL: string; readonly responseXML: Document | null; readonly status: number; readonly statusText: string; timeout: number; readonly upload: { addEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; }; withCredentials: boolean; abort: () => void; getAllResponseHeaders: () => string; getResponseHeader: (name: string) => string | null; open: { (method: string, url: string | URL): void; (method: string, url: string | URL, async: boolean, username?: string | null | undefined, password?: string | null | undefined): void; }; overrideMimeType: (mime: string) => void; send: (body?: Document | XMLHttpRequestBodyInit | null | undefined) => void; setRequestHeader: (name: string, value: string) => void; readonly UNSENT: 0; readonly OPENED: 1; readonly HEADERS_RECEIVED: 2; readonly LOADING: 3; readonly DONE: 4; addEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; } | undefined; }[]; queue: { id: number; file: { readonly lastModified: number; readonly name: string; readonly webkitRelativePath: string; readonly size: number; readonly type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start?: number | undefined, end?: number | undefined, contentType?: string | undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }; progress: number; status: "done" | "uploading" | "error" | "queued" | "cancelled"; error?: string | undefined; xhr?: { onreadystatechange: ((this: XMLHttpRequest, ev: Event) => any) | null; readonly readyState: number; readonly response: any; readonly responseText: string; responseType: XMLHttpRequestResponseType; readonly responseURL: string; readonly responseXML: Document | null; readonly status: number; readonly statusText: string; timeout: number; readonly upload: { addEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; }; withCredentials: boolean; abort: () => void; getAllResponseHeaders: () => string; getResponseHeader: (name: string) => string | null; open: { (method: string, url: string | URL): void; (method: string, url: string | URL, async: boolean, username?: string | null | undefined, password?: string | null | undefined): void; }; overrideMimeType: (mime: string) => void; send: (body?: Document | XMLHttpRequestBodyInit | null | undefined) => void; setRequestHeader: (name: string, value: string) => void; readonly UNSENT: 0; readonly OPENED: 1; readonly HEADERS_RECEIVED: 2; readonly LOADING: 3; readonly DONE: 4; addEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; } | undefined; }[]; }

Exposed

NameTypeDescription
start() => void
clear() => { id: number; file: { readonly lastModified: number; readonly name: string; readonly webkitRelativePath: string; readonly size: number; readonly type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start?: number | undefined, end?: number | undefined, contentType?: string | undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }; progress: number; status: "done" | "uploading" | "error" | "queued" | "cancelled"; error?: string | undefined; xhr?: { onreadystatechange: ((this: XMLHttpRequest, ev: Event) => any) | null; readonly readyState: number; readonly response: any; readonly responseText: string; responseType: XMLHttpRequestResponseType; readonly responseURL: string; readonly responseXML: Document | null; readonly status: number; readonly statusText: string; timeout: number; readonly upload: { addEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; }; withCredentials: boolean; abort: () => void; getAllResponseHeaders: () => string; getResponseHeader: (name: string) => string | null; open: { (method: string, url: string | URL): void; (method: string, url: string | URL, async: boolean, username?: string | null | undefined, password?: string | null | undefined): void; }; overrideMimeType: (mime: string) => void; send: (body?: Document | XMLHttpRequestBodyInit | null | undefined) => void; setRequestHeader: (name: string, value: string) => void; readonly UNSENT: 0; readonly OPENED: 1; readonly HEADERS_RECEIVED: 2; readonly LOADING: 3; readonly DONE: 4; addEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; } | undefined; }[]
queue{ id: number; file: { readonly lastModified: number; readonly name: string; readonly webkitRelativePath: string; readonly size: number; readonly type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start?: number | undefined, end?: number | undefined, contentType?: string | undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }; progress: number; status: "done" | "uploading" | "error" | "queued" | "cancelled"; error?: string | undefined; xhr?: { onreadystatechange: ((this: XMLHttpRequest, ev: Event) => any) | null; readonly readyState: number; readonly response: any; readonly responseText: string; responseType: XMLHttpRequestResponseType; readonly responseURL: string; readonly responseXML: Document | null; readonly status: number; readonly statusText: string; timeout: number; readonly upload: { addEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; }; withCredentials: boolean; abort: () => void; getAllResponseHeaders: () => string; getResponseHeader: (name: string) => string | null; open: { (method: string, url: string | URL): void; (method: string, url: string | URL, async: boolean, username?: string | null | undefined, password?: string | null | undefined): void; }; overrideMimeType: (mime: string) => void; send: (body?: Document | XMLHttpRequestBodyInit | null | undefined) => void; setRequestHeader: (name: string, value: string) => void; readonly UNSENT: 0; readonly OPENED: 1; readonly HEADERS_RECEIVED: 2; readonly LOADING: 3; readonly DONE: 4; addEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void; }; removeEventListener: { <K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void; }; onabort: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onerror: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onload: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadend: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; onprogress: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null; dispatchEvent: (event: Event) => boolean; } | undefined; }[]

Released under the MIT License. Character names and artwork belong to their owners.