Recipe

Avatar Upload UX

Drag-and-drop with instant preview, crop, and progressive enhancement.

Ingredients

  • File input with accept="image/*"
  • Drag-over visual feedback via onDragEnter/onDragLeave
  • Client-side preview with URL.createObjectURL
  • 160×160 circular crop mask overlay
  • Upload progress bar with XMLHttpRequest.upload
  • Error states: file too large, wrong type, network failure

Steps

  1. Render a hidden <input type="file">.
  2. Wrap a clickable drop zone that delegates to the input.
  3. On file selection, call URL.createObjectURL(file) and set preview state.
  4. Show the preview inside a circular container with a dashed border.
  5. On submit, POST to your upload endpoint with FormData.
  6. Track upload progress via xhr.upload.onprogress.
  7. On success, swap preview to the returned permanent URL.

Edge Cases

File too large

Validate size client-side before upload. Show clear max-size label.

Unsupported format

Check MIME type. Reject with inline error, do not clear the input.

Network failure

Retry button with exponential backoff. Preserve selected file.

Revoke object URLs

Call URL.revokeObjectURL on unmount or new selection.