File upload · dropzone

Drag-and-drop, paste or browse; files are checked for type, size and count, images get thumbnails, and each upload has its own progress, cancel and retry — as a dropzone, a compact bar, or a round avatar.

Drop, paste or browse · checked · uploaded one by one, each can be cancelled or retried

one fails on purpose, one isn't allowed
Attachments0 / 6

Click to upload or drag and drop

IMAGE, PDF, XLSX, DOCX · up to 5.0 MB · max 6 files · or paste with ⌘V

Compact · upload when you say so

Choose files or drag them herePDF, DOCX, TXT · up to 10 MB

Avatar · a ring shows the progress

Profile pictureSquare works best · PNG or JPG up to 2 MB

Usage

JavaScript
import { signal } from "./index.js";import { FileUpload } from "./components/upload.js"; const files = signal([]);   // entries: { file, name, size, preview, status(), progress(), error(), result }FileUpload({ value: files, accept: "image/*,.pdf", maxSize: 5e6, maxFiles: 6,  upload: (file, { onProgress, signal }) => {          // any transport — here XHR for upload progress    return new Promise((ok, fail) => {      const x = new XMLHttpRequest(); x.open("POST", "/upload");      x.upload.onprogress = (e) => onProgress(e.loaded / e.total);      x.onload = () => (x.status < 300 ? ok(JSON.parse(x.response)) : fail(new Error(x.statusText)));      x.onerror = () => fail(new Error("Network error"));      signal.addEventListener("abort", () => x.abort());      const fd = new FormData(); fd.append("file", file); x.send(fd);    });  } })FileUpload({ variant: "compact", autoUpload: false, upload })   // an "Upload n files" buttonFileUpload({ variant: "avatar", accept: "image/*", upload })    // round, with a progress ring