Hosted oneric.vicenti.netvia theHypermedia Protocol

    React Virtualization for Large Lists and Trees

    Problem

      Users experience UI lag and unresponsiveness when:

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

        1

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

        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