Skip to content
Development
Skill

/web-files-file-upload-patterns

File upload patterns - drag-drop dropzones, chunked and resumable uploads, presigned URL flows, file validation (MIME type, magic bytes), progress tracking, accessibility (ARIA)

From plugin
skills
26200 skills

Claude Code

$ npx -y skills add agents-inc/skills --skill web-files-file-upload-patterns --agent claude-code

SKILL.md

web-files-file-upload-patterns.SKILL.md
name: web-files-file-upload-patterns
description: File upload patterns - drag-drop dropzones, chunked and resumable uploads, presigned URL flows, file validation (MIME type, magic bytes), progress tracking, accessibility (ARIA)

File Upload Patterns

> **Quick Guide:** A dropzone is a keyboard-operable button wrapping a hidden file input, with drag > as an enhancement. Validate for the user's benefit on the client — extension, MIME type, then the > file's own magic bytes — and again on the server, because none of the client checks are security. > Progress needs `XMLHttpRequest`; `fetch` has no upload progress event. Past roughly 100MB, chunk > the file so a failure costs one chunk. Large files go straight to storage on a presigned URL the > server issues, so no request body is ever proxied.

**Detailed Resources:**

  • [examples/core.md](examples/core.md) — file input, dropzone, file list state and rendering, the assembled component
  • [examples/validation.md](examples/validation.md) — rule-based validator, magic-byte detection, dimension checks, a validation hook
  • [examples/progress.md](examples/progress.md) — XHR progress with speed and ETA, progress bar, formatters, concurrent uploads
  • [examples/preview.md](examples/preview.md) — a preview thumbnail for a selected file, with cleanup
  • [examples/presigned-upload.md](examples/presigned-upload.md) — PUT and POST-policy uploads, the server contract, multipart parts, the whole flow as a hook
  • [examples/resumable.md](examples/resumable.md) — chunked uploader with retry, resume across a reload, a tus client, the tus server contract
  • [examples/accessibility.md](examples/accessibility.md) — announcing selection and progress, focus return after the file dialog
  • [reference.md](reference.md) — method selection by size, expiry guidance, validation order, CORS, review checklist

---

Which path applies

The destination decides almost everything else.

  • **The file goes to your own endpoint** — one `POST` with `FormData`, progress from XHR, and a size

cap the server can enforce. [examples/core.md](examples/core.md) and [examples/progress.md](examples/progress.md) are the whole of it.

  • **The file goes to object storage** — the server issues a presigned URL and the browser uploads to

it directly, so no bytes pass through your application. [examples/presigned-upload.md](examples/presigned-upload.md).

  • **The file is large enough that a failure hurts** — split it, upload the parts with a concurrency

limit, and record which parts landed so a retry resumes. [examples/resumable.md](examples/resumable.md).

---

<critical_requirements>

Before writing upload code

**Validate on the server as well as in the browser.** Client validation exists to tell the user quickly what will be rejected; anyone can skip it entirely, so it settles nothing about safety.

**Read the file's first bytes when the type matters.** Extensions and MIME types are both supplied by whoever made the file, and a renamed executable passes every check that trusts them.

**Revoke every object URL you create.** A preview holds the whole file in memory until `URL.revokeObjectURL()` runs, so a user who changes their mind three times leaks three files.

**Make the dropzone reachable from the keyboard.** `role="button"`, `tabIndex={0}` and an Enter/Space handler that opens the file dialog, with drag layered on top — mobile has no drag at all, so the click path is the real one.

**Have the server issue a short-lived presigned URL rather than proxying the body.** The upload then costs your application nothing, and no storage credential is ever in reach of the browser.

</critical_requirements>

---

**Auto-detection:** dropzone, dataTransfer.files, dragenter, dragleave, dragover, input type="file", event.target.files, accept attribute, xhr.upload.addEventListener, lengthComputable, presigned URL, uploadUrl, multipart upload, UploadPart, ETag, chunked upload, file.slice, Content-Range, resumable upload, tus, Tus-Resumable, Upload-Offset, magic bytes, file signature, FormData append file

**Applies to:**

  • Selecting files by click, keyboard or drag
  • Validating type, size and dimensions before anything is sent
  • Reporting progress, speed and remaining time, and cancelling
  • Uploading straight to storage on a URL the server signed
  • Splitting a large file into chunks and resuming an interrupted upload
  • Announcing selection, progress and failure to a screen reader

**Handled elsewhere:**

  • Receiving, scanning and storing the bytes once they arrive
  • Resizing, cropping or converting an image before it is sent — this skill sends the `File` it is

given

  • Where the stored object lives, how it is served, and what its URL looks like
  • Streaming playback of media that was uploaded

---

<philosophy>

Philosophy

An upload is three independent problems that get conflated: choosing a file, checking it, and moving its bytes. Keeping them separate is what makes any of them replaceable.

The checking half has a rule that never bends. **Client validation is a user-experience feature, and the server's is the only one that is a control.** Everything the browser knows about a file — its name, its extension, its `type` — came from the file itself. Reading magic bytes raises the bar but does not change the category: it is still a check the client can be made to skip.

The moving half scales by a different axis: not how many files, but how long a single request is open. A short request can fail and be retried whole. A long one accumulates the probability of a dropped connection until retrying whole is unacceptable, and that is the point at which chunking starts paying for its complexity — not at a particular byte count.

</philosophy>

---

<patterns>

Core patterns

Pattern 1: Dropzone

Count drag events rather than tracking a boolean. `dragenter` and `dragleave` fire for every nested element, so a boolean flickers off the moment the pointer crosses a child.

Read more
@agents-inc
Ships withskills

The official skills marketplace for Agents Inc. 230+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Stars on GitHub

Momentum

stars in total
26
Star history of agents-inc/skills on GitHub, a chart by star-history.com

Other skills on skills.

ai-infrastructure-litellm

ai-infrastructure-lite…

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking,…

@agents-inc@agents-incInstall Skill
ai-infrastructure-modal

ai-infrastructure-moda…

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client…

@agents-inc@agents-incInstall Skill
ai-infrastructure-ollama

ai-infrastructure-olla…

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output,…

@agents-inc@agents-incInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about web-files-file-upload-patterns.

Which coding agents can use web-files-file-upload-patterns?
web-files-file-upload-patterns installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.