Skip to content

feat(core): implement built-in scroll-scaling for large lists#1172

Open
DivyamUp14 wants to merge 3 commits into
TanStack:mainfrom
DivyamUp14:feat/scroll-scaling
Open

feat(core): implement built-in scroll-scaling for large lists#1172
DivyamUp14 wants to merge 3 commits into
TanStack:mainfrom
DivyamUp14:feat/scroll-scaling

Conversation

@DivyamUp14
Copy link
Copy Markdown

@DivyamUp14 DivyamUp14 commented May 23, 2026

🎯 Changes

Fixes #616

Introduced native scroll-scaling in virtual-core to compress coordinates and bypass the browser's maximum scroll height limitation (~33.5 million pixels) for extremely large lists.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Added scroll-scaling to support extremely large virtualized lists
    • New option: maxScrollSize (default 33,000,000; Infinity disables scaling)
    • New property: scale exposes current scaling factor; scroll APIs operate transparently when scaling
  • Documentation

    • Updated API docs with scaling behavior, capped vs. virtual sizing, coordinate semantics, and usage guidance
  • Tests

    • Added tests covering scaling activation, coordinate/reporting behavior, and scroll anchoring under scaling

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62c3bb87-5b01-44db-90b9-64e79b6f6a26

📥 Commits

Reviewing files that changed from the base of the PR and between 431a45e and f40ad74.

📒 Files selected for processing (1)
  • packages/virtual-core/tests/index.test.ts

📝 Walkthrough

Walkthrough

This PR implements scroll-range scaling in TanStack Virtual's Virtualizer to handle virtual lists exceeding browser CSS height limits (~33.5 million pixels). It introduces a maxScrollSize configuration option and transparent virtual/physical coordinate conversion throughout the scroll event loop, item positioning, and sizing APIs, with comprehensive test coverage.

Changes

Scroll-Range Scaling Feature

Layer / File(s) Summary
Configuration and scale factor computation
packages/virtual-core/src/index.ts
Adds maxScrollSize?: number option to VirtualizerOptions (default 33_000_000), introduces internal getScale() computation, and exposes public scale getter returning the ratio of virtual total size to max scroll size.
Scaled item coordinates and sizing APIs
packages/virtual-core/src/index.ts
getVirtualItems() returns downscaled (physical) coordinates when scale !== 1, getTotalVirtualSize() tracks internal virtual measurements, getTotalSize() returns capped physical size, and getMaxScrollOffset() returns virtual-space maximum derived from the physical DOM max.
Scroll event reading and writing with coordinate conversion
packages/virtual-core/src/index.ts
Scroll event handler converts physical DOM offsets to virtual coordinates via scale; reconciliation tolerance is scaled; _scrollToOffset() downscales virtual offsets to physical coordinates before DOM write; _intendedScrollOffset recorded in physical space.
Comprehensive test coverage
packages/virtual-core/tests/index.test.ts
Tests validate scale computation, threshold behavior, custom maxScrollSize configuration, scaled getVirtualItems() coordinates and identity semantics, scale === 1 zero-overhead path, scroll offset upscaling/downscaling, and resize anchoring under active scaling.
API documentation and release notes
docs/api/virtualizer.md, .changeset/scroll-scaling.md
Documents maxScrollSize option and default behavior; clarifies getTotalSize() and scrollOffset semantics during scaling; expands scale property documentation with usage examples; release notes describe feature and behavioral guarantees.

🎯 3 (Moderate) | ⏱️ ~20 minutes


Possibly related PRs

  • TanStack/virtual#1168: Overlaps earlier scroll reconciliation and internal _intendedScrollOffset/rounding changes that interact with the scaling reconciliation math.

Suggested reviewers

  • piecyk

A rabbit hops through bounds so tall,
Where pixels once would break and fall,
Now scaling makes the viewport free,
Infinite lists we finally see! 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature added: implementing built-in scroll-scaling for large lists, which directly addresses the core changes in the PR.
Description check ✅ Passed The description follows the template structure, references the linked issue #616, explains the changes clearly, and confirms all checklist items are completed.
Linked Issues check ✅ Passed The PR successfully implements scroll-scaling to bypass browser max scroll height limits (#616) with new maxScrollSize option, scale property, and updated coordinate handling across all relevant functions.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing scroll-scaling: documentation updates, core implementation, test coverage, and a changeset entry—no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/virtual-core/tests/index.test.ts

Parsing error: "parserOptions.project" has been provided for @typescript-eslint/parser.
The file was not found in any of the provided project(s): packages/virtual-core/tests/index.test.ts


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/virtual-core/tests/index.test.ts (1)

2660-2677: ⚡ Quick win

The scale === 1 zero-overhead test doesn’t verify object identity yet.

This test currently checks size/scale only, so it won’t fail if getVirtualItems() starts cloning under scale === 1. Assert reference equality between returned items and getMeasurements() entries for visible indexes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/virtual-core/tests/index.test.ts` around lines 2660 - 2677, The test
currently only checks scale and total size but doesn't assert object identity;
update it to ensure getVirtualItems returns actual items (provide a non-null
scroll element in the Virtualizer config, e.g., a dummy element) when scale ===
1, call virtualizer.getMeasurements() and virtualizer.getVirtualItems(), then
for each virtual item assert strict reference equality with the corresponding
measurements entry (match by item.index) so the test fails if getVirtualItems
clones objects under scale === 1; keep existing getTotalSize and scale
assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/virtual-core/src/index.ts`:
- Around line 386-390: The getScale function can divide by invalid
options.maxScrollSize (0, negative, NaN, Infinity) causing invalid scale values;
update getScale to validate maxScrollSize before dividing (use Number.isFinite
and maxScrollSize > 0) and treat any invalid value as a safe fallback (e.g., 1
or a small positive clamp), keeping the existing behavior of returning
virtualTotal / max when valid; change references in getScale (and callers like
getTotalSize/offset conversion/anchoring logic) to rely on this validated result
so downstream math never sees Infinity/NaN/negative scale.

---

Nitpick comments:
In `@packages/virtual-core/tests/index.test.ts`:
- Around line 2660-2677: The test currently only checks scale and total size but
doesn't assert object identity; update it to ensure getVirtualItems returns
actual items (provide a non-null scroll element in the Virtualizer config, e.g.,
a dummy element) when scale === 1, call virtualizer.getMeasurements() and
virtualizer.getVirtualItems(), then for each virtual item assert strict
reference equality with the corresponding measurements entry (match by
item.index) so the test fails if getVirtualItems clones objects under scale ===
1; keep existing getTotalSize and scale assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a8f8b85-a408-461b-b026-09188d95fa4e

📥 Commits

Reviewing files that changed from the base of the PR and between 949180b and bbfc4bf.

📒 Files selected for processing (4)
  • .changeset/scroll-scaling.md
  • docs/api/virtualizer.md
  • packages/virtual-core/src/index.ts
  • packages/virtual-core/tests/index.test.ts

Comment thread packages/virtual-core/src/index.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reach browser max height pixels

1 participant