Menu
GitHub Engineering·September 23, 2026

Optimizing Large Pull Request Rendering in GitHub Copilot

This article delves into the architectural challenges of rendering extremely large pull requests within the GitHub Copilot app, focusing on maintaining UI performance and responsiveness. It highlights how the unpredictable nature of comment heights breaks traditional virtualization techniques and describes a hybrid geometry approach to manage deterministic code lines and dynamic comment blocks effectively. The solution involves a carefully designed measurement scheduler and scroll anchoring to prevent UI jank.

Read original on GitHub Engineering

The core problem addressed by GitHub Engineering in the Copilot app is rendering pull requests that are

The Challenge of Rendering Dynamic Content in Virtualized Lists

Traditional UI virtualization relies on knowing element heights upfront to calculate scrollbar dimensions and positions efficiently. For code diffs, where each line has a consistent height, this "all heights known before paint" contract works well. However, integrating dynamic content like review comments, whose heights vary based on markdown rendering, user interactions (expanding/collapsing sections, typing replies), and image loading, breaks this contract. Estimating heights leads to visual artifacts like whitespace gaps or clipped content, and updating heights after render causes jarring scroll jumps.

Two Geometries for Hybrid Content

To overcome the limitations of a single geometry, GitHub Copilot adopted a hybrid approach by splitting the document's total height into two independent domains:

  • Deterministic Code Height: Governed by the original "all heights known before paint" contract, using imperative, recycled row renderers and typed-array geometry for efficient offset math. This part is exact and never rebuilt due to comment resizing.
  • Dynamic Block Effective Heights: For unpredictable content like comments, drafts, and reply composers. Each dynamic block has a stable key, a content fingerprint, and records its last measured width. Its effective height is determined by actual measurement, a cached value (if fingerprint/width match), or an estimate.

Measurement Scheduler and Scroll Anchoring

A crucial innovation is the single idle- and scroll-gated measurement pass, replacing per-block ResizeObservers which caused feedback loops. This pass:

  • Runs off the hot path, only when scrolling settles and scoped to the viewport (O(viewport) work).
  • Prioritizes on-screen reads, performing a single batch read for all mounted candidates.
  • Uses off-screen rendering as a bounded fallback for nearby, unmounted blocks.
  • Maintains per-block ResizeObservers primarily for flagging, only performing synchronous measurements for directly user-caused changes in *mounted, on-screen* blocks, with safeguards against re-triggering loops.

To prevent scroll jumps when heights change, a scroll anchoring mechanism corrects by *identity* rather than *pixel position*. It captures the user's anchored element (row or block) and its offset, applies height deltas, and then repositions the viewport to keep the anchor stable. Special rules are applied for changes above/below the viewport, direct user interactions, and to avoid fighting active scroll momentum, ensuring a smooth user experience even with significant layout changes.

UIVirtualizationWeb PerformanceFrontend ArchitectureScrollingDiff RenderingUser ExperienceReact

Comments

Loading comments...