Show the file before upload

Render the picked file from its local copy now; upload behind it.

Guillermo Rauch7 Principles of Rich Web Applications
We can capture the user's intent to upload through a variety of means: drag and drop, paste, file picker. Then, thanks to new HTML5 APIs we can display content as if it had been uploaded.
rauchg.com · 2014Read article ↗
Guillermo Rauch@rauchg
Thoughts on rendering the image optimistically from the local reference? Rn it’s causing a layout shift
Feb 12, 2025View on X ↗
Guillermo Rauch@rauchg
I'm so impressed with @telegram's engineering … ▪️ Media uploads are fast and… convey progress
Dec 28, 2020View on X ↗

Demo 1 renders the local file with no shift, as his 2025 post asks; demo 2 is Telegram’s.

1 · Send a photo in chat

Send a sample, or pick, drop or paste your own image.

or drop / paste onto a chat
Wait for the uploadBad
Visible after —Shift —
Local copy, sizedGood
Visible after —Shift —
async function send(file) {
  const src = URL.createObjectURL(file);
  const { width, height } = await createImageBitmap(file);
  const msg = addMessage({ src, width, height, progress: 0 }); // aspect-ratio: width / height

  const xhr = new XMLHttpRequest();
  xhr.upload.onprogress = (e) => msg.setProgress(e.loaded / e.total);
  xhr.onload = () => { msg.sent(); URL.revokeObjectURL(src); };
  xhr.onerror = () => msg.failed({ retry: () => send(file) }); // keep the file
  xhr.open("POST", "/api/upload");
  xhr.send(file);
}

2 · Progress you can trust

Send an album, then stall the network halfway.

One spinnerBad
idle
Bytes, per photoGood
idle

Why it matters, pros and cons

Why it matters

The file is already on the device. Show it now; the upload is bookkeeping.

Pros

  • The photo appears the frame it’s picked, not seconds later.
  • Width and height come from the file, so nothing shifts.
  • Progress on the real image says moving, or stuck.

Cons

  • Object URLs hold memory until you revoke them.
  • Failure must keep the file and offer Retry, not drop it.
  • Server crops or filters can differ from the local preview.