Skip to the solution
HardMachine Coding13 min read

Build a Virtualized List

1.1k views

The problem

Question presented to candidate: "We have a contacts screen that has to show 10,000 rows, and right now it renders every one of them and the page crawls. Build a list component that stays smooth by only putting the rows you can actually see into the DOM. Rows are a fixed 40px tall and the list box is 400px high."

Requirements:

  • Render 10,000 rows in a 400px scrollable box with a scrollbar that reflects the full list height.
  • Mount only the visible rows plus a small overscan (3 rows above and below), and keep that number constant while scrolling.
  • Show a status line such as "Showing 501-510 of 10,000 ยท 16 rows in the DOM".
  • Clamp correctly at the top and the bottom of the list; the last row must be reachable.
  • Keep the list keyboard-scrollable and give screen readers the real list size.

What a strong answer should cover:

  • The windowing maths: first = floor(scrollTop / rowHeight), last = floor((scrollTop + viewportHeight - 1) / rowHeight), then widen by the overscan and clamp to [0, count - 1].
  • A spacer element whose height is count * rowHeight, with rows absolutely positioned at index * rowHeight, so the native scrollbar stays honest.
  • What is state (only the scroll position or the derived range) versus what is derived (the slice of rows), and re-rendering only when the range actually changes.
  • Overscan as a trade-off between blank flashes during fast scrolls and extra DOM work.
  • Stable keys (item id, not loop position) and ARIA: role="list", aria-setsize, aria-posinset, a focusable scroll container.
  • Limits: fixed versus variable row heights, browser maximum element height, find-in-page not seeing unmounted rows.

Clarifying questions expected:

  • "Are row heights fixed, or can they vary with content?"
  • "Does the list scroll inside a box or with the whole page?"
  • "Do we need selection, keyboard navigation between rows, or jump-to-row?"

Code / implementation expected: Yes. A working list component with the scroll handler, the range calculation, a spacer and absolutely positioned rows, ideally with the windowing maths in a small pure function.

  • React
  • Performance
  • Virtualization

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

13 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 VirtualList from "./src/components/VirtualList";

const TEAMS = ["Design", "Platform", "Growth", "Support", "Data"];

// 10,000 rows of fake contacts, built once at module load.
const ITEMS = Array.from({ length: 10000 }, (_, i) => ({
  id: i + 1,
  name: "Contact #" + String(i + 1).padStart(5, "0"),
  team: TEAMS[i % TEAMS.length],
}));

export default function App() {
  return (
    <main className="vl-app">
      <h1>Virtualized list: 10,000 contacts</h1>
      <VirtualList items={ITEMS} rowHeight={40} height={400} overscan={3} />
    </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 80 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 Dual Range (price) Slider

Continue