Skip to the solution
HardMachine Coding14 min read

Build a Drag-and-drop file uploader with configurable chunk size

752 views

The problem

Question presented to candidate: "Build a file uploader. Users drag files onto a drop zone or pick them with a button. Each file is uploaded in chunks, with a chunk size the user can choose. Show progress per file, let the user pause and resume, and retry chunks that fail. There is no real backend, so simulate the upload endpoint."

Requirements:

  • A drop zone that highlights while files are dragged over it, plus a "Browse files" button for keyboard and mouse users.
  • A chunk size selector (1 KB to 5 MB); each file is split with Blob.slice into byte ranges.
  • A simulated endpoint with latency and occasional failures, plus an "offline" switch.
  • Per-file progress (chunks done, percentage, a progressbar), with Pause, Resume and Retry buttons.
  • Up to 2 chunks in flight per file; failed chunks retry with exponential backoff, and a file fails after a few attempts.
  • When all chunks arrive, the server reassembles the file and the client checks that it matches.

What a strong answer should cover:

  • dragenter, dragover, dragleave and drop handling: preventDefault on dragover (or drop never fires), and a depth counter so child elements do not flicker the highlight.
  • A framework-free upload controller: a chunk plan, a concurrency-limited pump, retry with backoff, and AbortController for pause.
  • Keeping controller objects out of render state, and rendering immutable snapshots.
  • Resumability: only chunks not yet acknowledged are re-sent.
  • Edge cases: a 0-byte file, the last short chunk, and cleanup on unmount.

Clarifying questions expected:

  • "Does the real server support chunked or resumable uploads (for example S3 multipart or tus), and does it have a minimum part size?"
  • "How many files and chunks may upload at once?"
  • "Should pause survive a page reload?"

Code / implementation expected: Yes. The chunking and retry logic, the simulated server and the drop zone UI.

  • React
  • Drag and Drop
  • Upload

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

14 min read · 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import FileUploader from "./src/components/FileUploader";

const css = `
  body { margin: 0; background: #0f1115; color: #e6e6e6; font-family: system-ui, sans-serif; }
  .page { max-width: 600px; margin: 0 auto; padding: 20px 16px; }
  .up-opts { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; font-size: 14px; margin-bottom: 10px; color: #c9d1d9; }
  select { background: #171a21; color: #e6e6e6; border: 1px solid #2c3340; border-radius: 6px; padding: 4px 6px; }
  .up-zone { border: 2px dashed #3a4250; border-radius: 12px; padding: 28px 16px; text-align: center; background: #13161c; transition: background .15s, border-color .15s; }
  .up-zone.over { border-color: #f9a825; background: #1c140a; }
  .up-zone p { margin: 0 0 10px; color: #9aa4b2; }
  button { background: #222834; color: #e6e6e6; border: 1px solid #2c3340; border-radius: 8px; padding: 5px 12px; cursor: pointer; font: inherit; font-size: 13px; }
  .up-list { list-style: none; padding: 0; margin: 16px 0 0; display: flex; flex-direction: column; gap: 10px; }
  .up-list li { background: #171a21; border: 1px solid #2c3340; border-radius: 10px; padding: 10px 12px; }
  .up-row { display: flex; justify-content: space-between; gap: 8px; align-items: center; flex-wrap: wrap; font-size: 14px; }
  .up-meta, .up-status { color: #9aa4b2; font-size: 12px; word-break: break-word; }
  .up-bar { height: 6px; background: #262c36; border-radius: 3px; margin: 8px 0; overflow: hidden; }
  .up-fill { height: 100%; background: #f9a825; transition: width .2s; }
  .up-fill.done { background: #66bb6a; } .up-fill.error { background: #ef5350; } .up-fill.paused { background: #8b949e; }
`;

export default function App() {
  return (
    <main className="page">
      <style>{css}</style>
      <h1 style={{ fontSize: 18 }}>Upload files</h1>
      <FileUploader />
    </main>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 88 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

Build a Mini Spreadsheet (Excel)

Continue