# 6660 MINVirtualized List
# 66
60 MIN
Overview
Build a virtualized list that mounts only the rows visible in the scroll viewport (plus a small overscan) instead of rendering all 10,000 contacts at once, using fixed row heights and windowing math.
Requirements
- The app renders a virtualized directory of 10,000 contacts.
- Only a small window of rows is mounted in the DOM — far fewer than the 10,000 contacts in the dataset.
- The first contacts are rendered on load (including
data-testid="virtual-row-1"). - The scroll container (
data-testid="virtual-viewport") scrolls through the entire dataset, not just the mounted rows. - The scrollable area is sized to the full dataset (
data-testid="virtual-total"), so the scrollbar spans the whole list. - Scrolling down unmounts the rows above the viewport and mounts the rows that enter it.
- Scrolling back to the top restores the first rows.
- Scrolling to the bottom mounts the last contact.
- A few rows above and below the visible window are mounted too (overscan), more than the number that fit on screen.
- The stats line (
data-testid="virtual-stats") shows the first and last mounted row numbers:Showing X–Y of 10000. - Each row (
data-testid="virtual-row-<id>") shows the contact's name and email. - No rows are mounted before the first contact (indices never go negative).
Notes
data.tsandComponents.tsxare read-only.VirtualViewportis the scroll box and callsonScroll(scrollTop);VirtualRowis aROW_HEIGHT-tall row that shows the contact's name and email;VirtualStatsshowsShowing X–Y of N.ROW_HEIGHTis exported fromComponents; derive the total withCONTACTS.length.- Put all the windowing logic in
App.tsx: trackscrollTop, measure the viewport'sclientHeight, and compute the range of rows to mount. - Measure the viewport height in a layout effect (
viewportRef.current.clientHeight); the viewport is styledh-96. - The mounted rows must stay visually aligned with their position in the dataset as you scroll.
- Keep rows keyed by
contact.id. - Clamp the range so overscan never renders rows before the first or after the last contact (indices never go negative).
- The tests simulate the viewport by mocking
clientHeightand dispatchingscrollevents with a fakescrollTop.
Tests
- renders the app title
- only mounts a small window of rows, not the whole dataset
- renders the first contacts on load
- sizes the scrollable area to the full dataset
- shows the first and last rendered rows in the stats
- renders more rows than fit on screen (overscan)
- shows the name and email for each mounted row
- moves the window down when scrolling
- restores the first rows when scrolling back to the top
- renders the last contact when scrolled to the bottom
- mounts overscan rows above the visible window when scrolled
- never renders rows above the first one