Big lists, cheap keystrokes

Render only visible rows and keep each keystroke under a frame.

Web Interface Guidelinesvercel-labs · command.md
- Large lists (>50 items): virtualize (`virtua`, `content-visibility: auto`) - No layout reads in render (`getBoundingClientRect`, `offsetHeight`, `offsetWidth`, `scrollTop`) - Batch DOM reads/writes; avoid interleaving - Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
PerformanceView source ↗
Web Interface Guidelinesvercel-labs · command.md
- Large arrays `.map()` without virtualization
Anti-patterns listView source ↗
Web Interface Guidelinesvercel-labs · command.md
- Flex/grid over JS measurement for layout
Safe Areas & LayoutView source ↗
virtuainokawa · GitHub
A zero-config, fast and small virtual list and grid component for React, Vue, Solid, Svelte and Angular.
The library the guideline namesView repo ↗

From web-design-guidelines (Web Interface Guidelines).

Mount a long list

Remount, then toggle Dense rows. Compare the costs.

.map() every rowBad
Rows in DOM
–
Mount
–
Relayout
–
content-visibilityCheaper
Rows in DOM
–
Mount
–
Relayout
–
Virtualized windowGood
Rows in DOM
–
Mount
–
Relayout
–
const start = Math.floor(viewport.scrollTop / ROW_H) - OVERSCAN;
const end = start + Math.ceil(viewH / ROW_H) + OVERSCAN * 2;
.row { content-visibility: auto; contain-intrinsic-size: auto 32px; }

Filter while typing

Type fast in each box, or press Type for me.

Renders every matchBad
Last key
–
Worst
–
Over 50 ms
–
Matches
–
Uncontrolled, windowedGood
Last key
–
Worst
–
Over 50 ms
–
Matches
–
<input type="search" defaultValue="" onInput={onQuery} />
const q = useDeferredValue(query);

Read, then write

Press Resize all, then raise the box count.

InterleavedBad
Layout passes
–
Time to paint
–
BatchedGood
Layout passes
–
Time to paint
–
const widths = boxes.map((b) => b.offsetWidth);
boxes.forEach((b, i) => (b.style.width = `${next(widths[i])}px`));

Why it matters, pros and cons

Why it matters

Every DOM node costs layout, yet readers see about twenty rows.

Pros

  • Mount cost stays flat at any size.
  • Keystrokes paint within a frame.
  • N forced layouts become one.

Cons

  • Find-in-page and screen readers see only the window.
  • Variable row heights need measuring or a library.
  • Under ~50 rows it is pure overhead.