Hosted onnoosphere.hyper.mediavia theHypermedia Protocol

React Virtualization for Large Lists and Trees

Problem

Users experience UI lag and unresponsiveness when:

  1. Opening large documents — A document with 100+ nested blocks/sections causes slow initial render and janky scrolling as React mounts the entire tree

  2. Viewing discussion feeds — Long lists of comments/discussions (50+) bog down the UI, especially on lower-powered devices

  3. Browsing document lists — Feeds showing many document cards (homepage, search results) become sluggish

The source data is fine to keep in memory. The bottleneck is React's reconciliation + DOM mounting — we're rendering hundreds of components that aren't even visible.

Solution

Implement windowing/virtualization to render only visible items. Two libraries depending on data structure.

We might choose to use one or both of these libraries. It is undecided which is best, so we should experiment with both or even more.

Our documents have existing expand/collapse behavior which we would need to rewrite.

Pre-Solution

We should ensure that we are using clever memoization when rendering docs and long lists. This is an easier fix that would mitigate the demand for this project.

Flat Lists → @tanstack/react-virtual

For discussions, feeds, and simple document lists:

const virtualizer = useVirtualizer({
  count: items.length,
  getScrollElement: () => containerRef.current,
  estimateSize: () => 80, // estimated row height
})

// Only render virtualizer.getVirtualItems() — typically 10-20 items

Open question: How do we handle variable-height items? TanStack supports measureElement for dynamic sizing but adds complexity.

Hierarchical Data → react-arborist

For document outline/block trees:

<Tree
  data={documentBlocks}
  width={containerWidth}
  height={containerHeight}
  rowHeight={32}
>
  {({ node, style }) => <BlockRenderer node={node} style={style} />}
</Tree>

Handles expand/collapse and only renders visible nodes automatically.

Open question: How does this integrate with our current recursive block rendering? We'd need to flatten our tree model or adapt our renderers to arborist's API.

Integration Points

  • DiscussionList — flat virtualization

  • DocumentOutline / sidebar tree — arborist

  • BlockEditor content area — needs investigation (may conflict with editor state)

  • FeedView (home, search results) — flat virtualization

Scope

  • Frontend only — no backend changes

  • Medium effort — 1-2 weeks depending on how deeply embedded current rendering is

  • Affects: packages/app, possibly packages/editor

  • No design changes required (virtualization is invisible to users when done right)

Rabbit Holes

  • Editor integration — Does virtualizing blocks break selection, cursor position, or collaborative editing state?

  • Scroll restoration — Virtualized lists lose scroll position on re-mount; need to persist/restore

  • Dynamic heights — If block heights vary significantly, measurement overhead may negate perf gains

  • Animations — Current expand/collapse animations may not play nicely with virtualization

No Goes

  • Pagination/lazy loading from backend — This project is about render performance, not data fetching

  • Rewriting the editor — We virtualize around the editor, not inside it (for now)

  • Mobile-specific optimizations — Same solution should work everywhere; no platform branching

  • Server-side rendering changes — Virtualization is client-only concern

Do you like what you are reading?. Subscribe to receive updates.

Unsubscribe anytime