SayUI
Content & display

Virtual List / Windowing

Render only the visible window of a long list and recycle nodes as the user scrolls.

Also known as virtual scroll · windowed list · recycled list

Demo · not production-ready code

Prompt for AI

Pick a stack, copy a ready prompt, paste into Cursor / Claude / ChatGPT.

Your stack

Shapes the prompt you copy

React + Tailwind + shadcn/ui · EN

Stack: React + Tailwind + shadcn/ui. Use React with Tailwind CSS and shadcn/ui patterns (Radix-based primitives, cn(), class-first styling).

Task: implement "Virtual List / Windowing".

Virtualize the order list for up to 10k rows: render the visible window plus ~5 rows of overscan, a spacer for true scroll height, stable data ids as keys. Prefer fixed row height first; measure if heights vary. Skip virtualization under a few hundred rows.

Anatomy:
- viewport / window: The rows actually mounted.
- spacer / total size: Keeps the scrollbar honest for the full dataset.
- overscan: Extra rows above/below so fast scrolls don’t flash empty.
- recycling: DOM nodes leave the window and host new data.

Preferred API / pattern: `react-window / @tanstack/virtual / virtua`

Keep scope minimal: only this UI pattern, match existing project style.

Acceptance checks

  • ○Avoid: Virtualizing dozens of rows
  • ○Avoid: Variable heights assumed fixed
  • ○Avoid: Fast scroll white gaps
  • ○Avoid: Keys are array indexes
  • ○Avoid: Forgetting Ctrl/Cmd+F is broken

In plain wordsHow people search for it

“a huge list that still scrolls smooth because it only draws what’s on screen”“ten thousand rows without melting the browser”“recycling row DOM as I scroll instead of mounting everything”

AnatomyOpen for part names

viewport / window
The rows actually mounted.
spacer / total size
Keeps the scrollbar honest for the full dataset.
overscan
Extra rows above/below so fast scrolls don’t flash empty.
recycling
DOM nodes leave the window and host new data.

How to write itOpen for stack patterns

Web (HTML/CSS)windowing libs / content-visibility: auto
React + Tailwind + shadcn/uireact-window / @tanstack/virtual / virtua
SwiftUILazyVStack / List (lazy by default)
Ant Designvirtual prop on Table/List / rc-virtual-list

Notes

Not a widget—a strategy. DOM count kills long lists; windowing turns 10k rows into ~20. Cost: in-page find won’t see unmounted rows, a11y trees are partial, variable heights get hard. Don’t virtualize a 40-row table—that’s over-engineering.

Common mistakesHumans and models trip here

  • Virtualizing dozens of rows: complexity with no payoff.
  • Variable heights assumed fixed: scrollbar jumps and hit targets lie.
  • Fast scroll white gaps: raise overscan and skeleton placeholders.
  • Keys are array indexes: recycled rows keep the wrong checkbox state—use ids.
  • Forgetting Ctrl/Cmd+F is broken: ship an explicit search field.

More failure symptoms on AI broke it.

Related patterns

Spotted a wrong name or missing pattern?

Message on X