Showing preview only (658K chars total). Download the full file or copy to clipboard to get everything.
Repository: TanStack/virtual
Branch: main
Commit: c9397853af6c
Files: 515
Total size: 550.6 KB
Directory structure:
gitextract_lr2rhb18/
├── .changeset/
│ └── config.json
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ └── config.yml
│ ├── pull_request_template.md
│ ├── renovate.json
│ └── workflows/
│ ├── autofix.yml
│ ├── pr.yml
│ └── release.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs/
│ ├── api/
│ │ ├── virtual-item.md
│ │ └── virtualizer.md
│ ├── config.json
│ ├── framework/
│ │ ├── angular/
│ │ │ └── angular-virtual.md
│ │ ├── lit/
│ │ │ └── lit-virtual.md
│ │ ├── react/
│ │ │ └── react-virtual.md
│ │ ├── solid/
│ │ │ └── solid-virtual.md
│ │ ├── svelte/
│ │ │ └── svelte-virtual.md
│ │ └── vue/
│ │ └── vue-virtual.md
│ ├── installation.md
│ └── introduction.md
├── eslint.config.js
├── examples/
│ ├── angular/
│ │ ├── dynamic/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ ├── app.config.ts
│ │ │ │ │ ├── app.routes.ts
│ │ │ │ │ ├── column-virtualizer-dynamic.component.ts
│ │ │ │ │ ├── grid-virtualizer-dynamic.component.ts
│ │ │ │ │ ├── row-virtualizer-dynamic-window.component.ts
│ │ │ │ │ ├── row-virtualizer-dynamic.component.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── fixed/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ ├── column-virtualizer-fixed.component.ts
│ │ │ │ │ ├── grid-virtualizer-fixed.component.ts
│ │ │ │ │ └── row-virtualizer-fixed.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── infinite-scroll/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ └── app.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── padding/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ ├── column-virtualizer-padding.component.ts
│ │ │ │ │ ├── grid-virtualizer-padding.component.ts
│ │ │ │ │ └── row-virtualizer-padding.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── smooth-scroll/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ └── app.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── sticky/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ └── app.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── table/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ └── make-data.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ ├── variable/
│ │ │ ├── .devcontainer/
│ │ │ │ └── devcontainer.json
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── angular.json
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── app/
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ ├── column-virtualizer-variable.component.ts
│ │ │ │ │ ├── grid-virtualizer-variable.component.ts
│ │ │ │ │ └── row-virtualizer-variable.component.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── styles.css
│ │ │ ├── tsconfig.app.json
│ │ │ └── tsconfig.json
│ │ └── window/
│ │ ├── .devcontainer/
│ │ │ └── devcontainer.json
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── angular.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ └── app.component.ts
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ └── styles.css
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.json
│ ├── lit/
│ │ ├── dynamic/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ └── fixed/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.css
│ │ │ └── main.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.js
│ ├── react/
│ │ ├── dynamic/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── fixed/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── infinite-scroll/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── padding/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── scroll-padding/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── smooth-scroll/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── sticky/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── table/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ ├── main.tsx
│ │ │ │ └── makeData.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── variable/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── index.css
│ │ │ │ └── main.tsx
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ └── window/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.css
│ │ │ └── main.tsx
│ │ ├── tsconfig.json
│ │ └── vite.config.js
│ ├── svelte/
│ │ ├── dynamic/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── ColumnVirtualizerDynamic.svelte
│ │ │ │ ├── GridVirtualizerDynamic.svelte
│ │ │ │ ├── RowVirtualizerDynamic.svelte
│ │ │ │ ├── RowVirtualizerDynamicWindow.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── main.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── svelte.config.js
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ └── vite.config.ts
│ │ ├── fixed/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── ColumnVirtualizerFixed.svelte
│ │ │ │ ├── GridVirtualizerFixed.svelte
│ │ │ │ ├── RowVirtualizerFixed.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── main.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── svelte.config.js
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ └── vite.config.ts
│ │ ├── infinite-scroll/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── InfiniteRows.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── main.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── svelte.config.js
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ └── vite.config.ts
│ │ ├── smooth-scroll/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── main.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── svelte.config.js
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ └── vite.config.ts
│ │ ├── sticky/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── main.ts
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── svelte.config.js
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ └── vite.config.ts
│ │ └── table/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.svelte
│ │ │ ├── app.css
│ │ │ ├── main.ts
│ │ │ ├── makeData.ts
│ │ │ └── vite-env.d.ts
│ │ ├── svelte.config.js
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── vue/
│ ├── dynamic/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── components/
│ │ │ │ ├── ColumnVirtualizerDynamic.vue
│ │ │ │ ├── GridVirtualizerDynamic.vue
│ │ │ │ ├── RowVirtualizerDynamic.vue
│ │ │ │ ├── RowVirtualizerDynamicWindow.vue
│ │ │ │ └── utils.ts
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── fixed/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── components/
│ │ │ │ ├── ColumnVirtualizerFixed.vue
│ │ │ │ ├── GridVirtualizerFixed.vue
│ │ │ │ └── RowVirtualizerFixed.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── infinite-scroll/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── padding/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── components/
│ │ │ │ ├── ColumnVirtualizerPadding.vue
│ │ │ │ ├── GridVirtualizerPadding.vue
│ │ │ │ └── RowVirtualizerPadding.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── scroll-padding/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── smooth-scroll/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── sticky/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── main.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── table/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── main.ts
│ │ │ ├── makeData.ts
│ │ │ ├── style.css
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── variable/
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src/
│ │ ├── App.vue
│ │ ├── components/
│ │ │ ├── ColumnVirtualizerVariable.vue
│ │ │ ├── GridVirtualizerVariable.vue
│ │ │ ├── MasonryHorizontalVirtualizerVariable.vue
│ │ │ ├── MasonryVerticalVirtualizerVariable.vue
│ │ │ └── RowVirtualizerVariable.vue
│ │ ├── main.ts
│ │ ├── style.css
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── knip.json
├── media/
│ └── logo.sketch
├── nx.json
├── package.json
├── packages/
│ ├── angular-virtual/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── ng-package.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── proxy.ts
│ │ │ └── types.ts
│ │ ├── tsconfig.build.json
│ │ └── tsconfig.json
│ ├── lit-virtual/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ └── index.test.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── react-virtual/
│ │ ├── CHANGELOG.md
│ │ ├── e2e/
│ │ │ └── app/
│ │ │ ├── measure-element/
│ │ │ │ ├── index.html
│ │ │ │ └── main.tsx
│ │ │ ├── scroll/
│ │ │ │ ├── index.html
│ │ │ │ └── main.tsx
│ │ │ ├── smooth-scroll/
│ │ │ │ ├── index.html
│ │ │ │ └── main.tsx
│ │ │ ├── stale-index/
│ │ │ │ ├── index.html
│ │ │ │ └── main.tsx
│ │ │ ├── test/
│ │ │ │ ├── measure-element.spec.ts
│ │ │ │ ├── scroll.spec.ts
│ │ │ │ ├── smooth-scroll.spec.ts
│ │ │ │ └── stale-index.spec.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.ts
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── playwright.config.ts
│ │ ├── src/
│ │ │ └── index.tsx
│ │ ├── tests/
│ │ │ ├── index.test.tsx
│ │ │ └── test-setup.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── solid-virtual/
│ │ ├── CHANGELOG.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── svelte-virtual/
│ │ ├── CHANGELOG.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── svelte.config.js
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── virtual-core/
│ │ ├── CHANGELOG.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── utils.ts
│ │ ├── tests/
│ │ │ └── index.test.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ └── vue-virtual/
│ ├── CHANGELOG.md
│ ├── eslint.config.js
│ ├── package.json
│ ├── src/
│ │ └── index.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── pnpm-workspace.yaml
├── prettier.config.js
├── scripts/
│ └── verify-links.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
"changelog": [
"@svitejs/changesets-changelog-github-compact",
{ "repo": "TanStack/virtual" }
],
"commit": false,
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"fixed": [],
"linked": [],
"ignore": [],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto eol=lf
================================================
FILE: .github/FUNDING.yml
================================================
github: tannerlinsley
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐛 Bug Report
description: Report a reproducible bug or regression
body:
- type: markdown
attributes:
value: |
Thank you for reporting an issue :pray:.
This issue tracker is for reporting reproducible bugs or regression's found in [tanstack-virtual](https://github.com/tanstack/virtual)
If you have a question about how to achieve or implement something and are struggling, please post a question
inside of tanstack-virtual's [Discussions tab](https://github.com/tanstack/virtual/discussions) instead of filing an issue.
Before submitting a new bug/issue, please check the links below to see if there is a solution or question posted there already:
- tanstack-virtual's [Discussions tab](https://github.com/tanstack/virtual/discussions)
- tanstack-virtual's [Open Issues](https://github.com/tanstack/virtual/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
- tanstack-virtual's [Closed Issues](https://github.com/tanstack/virtual/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed)
The more information you fill in, the better the community can help you.
- type: textarea
id: description
attributes:
label: Describe the bug
description: Provide a clear and concise description of the challenge you are running into.
validations:
required: true
- type: input
id: link
attributes:
label: Your minimal, reproducible example
description: |
Please add a link to a minimal reproduction.
Note:
- Your bug may get fixed much faster if we can run your code and it doesn't have dependencies other than React.
- To create a shareable code example for web, you can use CodeSandbox (https://codesandbox.io/s/new) or Stackblitz (https://stackblitz.com/).
- Please make sure the example is complete and runnable without prior dependencies and free of unnecessary abstractions
- Feel free to fork any of the official CodeSandbox examples to reproduce your issue: https://github.com/tanstack/virtual/tree/main/examples/
- For React Native, you can use: https://snack.expo.dev/
- For TypeScript related issues only, a TypeScript Playground link might be sufficient: https://www.typescriptlang.org/play
- Please read these tips for providing a minimal example: https://stackoverflow.com/help/mcve.
placeholder: |
e.g. Code Sandbox, Stackblitz, Expo Snack or TypeScript playground
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: Describe the steps we have to take to reproduce the behavior.
placeholder: |
1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: Provide a clear and concise description of what you expected to happen.
placeholder: |
As a user, I expected **_ behavior but i am seeing _**
validations:
required: true
- type: dropdown
attributes:
options:
- Every time
- Often
- Sometimes
- Only once
label: How often does this bug happen?
description: |
Following the repro steps above, how easily are you able to reproduce this bug?
options: - Every time - Often - Sometimes - Only once
- type: textarea
id: screenshots_or_videos
attributes:
label: Screenshots or Videos
description: |
If applicable, add screenshots or a video to help explain your problem.
For more information on the supported file image/file types and the file size limits, please refer
to the following link: https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/attaching-files
placeholder: |
You can drag your video or image files inside of this editor ↓
- type: textarea
id: platform
attributes:
label: Platform
description: |
Please let us know which Operting System, Browser and Browser version you were using when the issue occurred.
placeholder: |
- OS: [e.g. macOS, Windows, Linux, iOS, Android] - Browser: [e.g. Chrome, Safari, Firefox, React Native] - Version: [e.g. 91.1]
validations:
required: true
- type: input
id: library-version
attributes:
label: tanstack-virtual version
description: |
Please let us know the exact version of tanstack-virtual you were using when the issue occurred. Please don't just put in "latest", as this is subject to change.
placeholder: |
e.g. v3.30.1
validations:
required: true
- type: input
id: ts-version
attributes:
label: TypeScript version
description: |
If you are using TypeScript, please let us know the exact version of TypeScript you were using when the issue occurred.
placeholder: |
e.g. v5.2.2
- type: textarea
id: additional
attributes:
label: Additional context
description: Add any other context about the problem here.
- type: checkboxes
id: agrees-to-terms
attributes:
label: Terms & Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct and can verify that you have followed the requirements outlined above to the best of your ability.
options:
- label: I agree to follow this project's Code of Conduct
required: true
- label: I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: 🤔 Feature Requests & Questions
url: https://github.com/TanStack/virtual/discussions
about: Please ask and answer questions here.
- name: 💬 Community Chat
url: https://discord.gg/mQd7egN
about: A dedicated discord server hosted by TanStack
- name: 🦋 TanStack Bluesky
url: https://bsky.app/profile/tanstack.com
about: Stay up to date with new releases of our libraries
================================================
FILE: .github/pull_request_template.md
================================================
## 🎯 Changes
<!-- What changes are made in this PR? Describe the change and its motivation. -->
## ✅ Checklist
- [ ] I have followed the steps in the [Contributing guide](https://github.com/TanStack/virtual/blob/main/CONTRIBUTING.md).
- [ ] I have tested this code locally with `pnpm run test:pr`.
## 🚀 Release Impact
- [ ] This change affects published code, and I have generated a [changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).
- [ ] This change is docs/CI/dev-only (no release).
================================================
FILE: .github/renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"configMigration": true,
"extends": [
"config:recommended",
"group:allNonMajor",
"schedule:weekly",
":approveMajorUpdates",
":automergeMinor",
":disablePeerDependencies",
":maintainLockFilesMonthly",
":semanticCommits",
":semanticCommitTypeAll(chore)"
],
"ignorePresets": [":ignoreModulesAndTests"],
"labels": ["dependencies"],
"rangeStrategy": "bump",
"postUpdateOptions": ["pnpmDedupe"],
"ignoreDeps": ["@types/node", "node", "typescript"]
}
================================================
FILE: .github/workflows/autofix.yml
================================================
name: autofix.ci # needed to securely identify the workflow
on:
pull_request:
push:
branches: [main, alpha, beta]
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
autofix:
name: autofix
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup Tools
uses: tanstack/config/.github/setup@main
- name: Fix formatting
run: pnpm format
- name: Apply fixes
uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef
with:
commit-message: 'ci: apply automated fixes'
================================================
FILE: .github/workflows/pr.yml
================================================
name: PR
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: true
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
permissions:
contents: read
pull-requests: write
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Setup Tools
uses: tanstack/config/.github/setup@main
- name: Get base and head commits for `nx affected`
uses: nrwl/nx-set-shas@v4.4.0
with:
main-branch-name: main
- name: Install Playwright browsers
run: pnpm exec playwright install chromium
- name: Run Checks
run: pnpm run test:pr
preview:
name: Preview
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup Tools
uses: tanstack/config/.github/setup@main
- name: Build Packages
run: pnpm run build:all
- name: Publish Previews
run: pnpx pkg-pr-new publish --pnpm --compact './packages/*' --template './examples/*/*'
provenance:
name: Provenance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Check Provenance
uses: danielroe/provenance-action@v0.1.1
with:
fail-on-downgrade: true
version-preview:
name: Version Preview
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup Tools
uses: TanStack/config/.github/setup@main
- name: Changeset Preview
uses: TanStack/config/.github/changeset-preview@main
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches: [main, alpha, beta]
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: true
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
permissions:
contents: write
id-token: write
pull-requests: write
jobs:
release:
name: Release
if: github.repository_owner == 'TanStack'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Setup Tools
uses: tanstack/config/.github/setup@main
- name: Install Playwright browsers
run: pnpm exec playwright install chromium
- name: Run Tests
run: pnpm run test:ci
- name: Run Changesets (version or publish)
id: changesets
uses: changesets/action@v1.7.0
with:
version: pnpm run changeset:version
publish: pnpm run changeset:publish
commit: 'ci: Version Packages'
title: 'ci: Version Packages'
- name: Comment on PRs about release
if: steps.changesets.outputs.published == 'true'
uses: TanStack/config/.github/comment-on-release@main
with:
published-packages: ${{ steps.changesets.outputs.publishedPackages }}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
package-lock.json
yarn.lock
# builds
build
coverage
dist
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.next
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.history
size-plugin.json
stats-hydration.json
stats.json
stats.html
.vscode/settings.json
*.log
.cache
.idea
.nx/cache
.nx/workspace-data
.pnpm-store
.tsup
.svelte-kit
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Playwright test artifacts
test-results/
playwright-report/
*.log
================================================
FILE: .npmrc
================================================
provenance=true
================================================
FILE: .nvmrc
================================================
24.8.0
================================================
FILE: .prettierignore
================================================
**/.next
**/.nx/cache
**/.svelte-kit
**/build
**/coverage
**/dist
**/docs
**/codemods/**/__testfixtures__
pnpm-lock.yaml
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
## Questions
If you have questions about implementation details, help or support, then please use our dedicated community forum at [GitHub Discussions](https://github.com/TanStack/virtual/discussions) **PLEASE NOTE:** If you choose to instead open an issue for your question, your issue will be immediately closed and redirected to the forum.
## Reporting Issues
If you have found what you think is a bug, please [file an issue](https://github.com/TanStack/virtual/issues/new/choose). **PLEASE NOTE:** Issues that are identified as implementation questions or non-issues will be immediately closed and redirected to [GitHub Discussions](https://github.com/TanStack/virtual/discussions)
## Suggesting new features
If you are here to suggest a feature, first create an issue if it does not already exist. From there, we will discuss use-cases for the feature and then finally discuss how it could be implemented.
## Development
If you have been assigned to fix an issue or develop a new feature, please follow these steps to get started:
- Fork this repository.
- Install dependencies
```bash
pnpm install
```
- We use [pnpm](https://pnpm.io/) v9 for package management (run in case of pnpm-related issues).
```bash
corepack enable && corepack prepare
```
- We use [nvm](https://github.com/nvm-sh/nvm) to manage node versions - please make sure to use the version mentioned in `.nvmrc`
```bash
nvm use
```
- Build all packages.
```bash
pnpm build:all
```
- Run development server.
```bash
pnpm run watch
```
- Implement your changes and tests to files in the `src/` directory and corresponding test files.
- Document your changes in the appropriate doc page.
- Git stage your required changes and commit (see below commit guidelines).
- Submit PR for review.
### Editing the docs locally and previewing the changes
The documentations for all the TanStack projects are hosted on [tanstack.com](https://tanstack.com), which is a TanStack Start application (https://github.com/TanStack/tanstack.com). You need to run this app locally to preview your changes in the `TanStack/virtual` docs.
> [!NOTE]
> The website fetches the doc pages from GitHub in production, and searches for them at `../virtual/docs` in development. Your local clone of `TanStack/virtual` needs to be in the same directory as the local clone of `TanStack/tanstack.com`.
You can follow these steps to set up the docs for local development:
1. Make a new directory called `tanstack`.
```sh
mkdir tanstack
```
2. Enter that directory and clone the [`TanStack/virtual`](https://github.com/TanStack/virtual) and [`TanStack/tanstack.com`](https://github.com/TanStack/tanstack.com) repos.
```sh
cd tanstack
git clone git@github.com:TanStack/virtual.git
# We probably don't need all the branches and commit history
# from the `tanstack.com` repo, so let's just create a shallow
# clone of the latest version of the `main` branch.
# Read more about shallow clones here:
# https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/#user-content-shallow-clones
git clone git@github.com:TanStack/tanstack.com.git --depth=1 --single-branch --branch=main
```
> [!NOTE]
> Your `tanstack` directory should look like this:
>
> ```
> tanstack/
> |
> +-- virtual/ (<-- this directory cannot be called anything else!)
> |
> +-- tanstack.com/
> ```
3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode:
```sh
cd tanstack.com
pnpm i
# The app will run on https://localhost:3000 by default
pnpm dev
```
4. Now you can visit http://localhost:3000/virtual/latest/docs/overview in the browser and see the changes you make in `TanStack/virtual/docs` there.
> [!WARNING]
> You will need to update the `docs/config.json` file (in `TanStack/virtual`) if you add a new documentation page!
You can see the whole process in the screen capture below:
https://github.com/fulopkovacs/form/assets/43729152/9d35a3c3-8153-4e74-9cb2-af275f7a269b
### Running examples
- Make sure you've installed the dependencies in the repo's root directory.
```bash
pnpm install
```
- If you want to run the example against your local changes, run below in the repo's root directory. Otherwise, it will be run against the latest TanStack Virtual release.
```bash
pnpm run watch
```
- Run below in the selected examples' directory.
```bash
pnpm run dev
```
#### Note on standalone execution
If you want to run an example without installing dependencies for the whole repo, just follow instructions from the example's README.md file. It will be then run against the latest TanStack Virtual release.
## Online one-click setup
You can use Gitpod (An Online Open Source VS Code like IDE which is free for Open Source) for developing online. With a single click it will start a workspace and automatically:
- clone the `TanStack/virtual` repo.
- install all the dependencies in `/` and `/docs`.
- run below in the root(`/`) to Auto-build files.
```bash
npm start
```
- run below in `/docs`.
```bash
npm run dev
```
[](https://gitpod.io/#https://github.com/TanStack/virtual)
## Changesets
This repo uses [Changesets](https://github.com/changesets/changesets) to automate releases. If your PR should release a new package version (patch, minor, or major), please run run `pnpm changeset` and commit the file. If needed, changeset descriptions can be more descriptive, and will be included in the changelog. If your PR affects docs, examples, styles, etc., you probably don't need to generate a changeset.
## Pull requests
Maintainers merge pull requests by squashing all commits and editing the commit message if necessary using the GitHub user interface.
Use an appropriate commit type. Be especially careful with breaking changes.
## Releases
For each new commit added to `main`, a GitHub Workflow is triggered which runs the [Changesets Action](https://github.com/changesets/action). This generates a preview PR showing the impact of all changesets. When this PR is merged, the package will be published to NPM.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021-present Tanner Linsley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<div align="center">
<img src="./media/header_virtual.png" alt="Tanstack Virtual">
</div>
<br />
<div align="center">
<a href="https://npmjs.com/package/@tanstack/virtual-core" target="\_parent">
<img alt="npm downloads" src="https://img.shields.io/npm/dm/@tanstack/virtual-core.svg" />
</a>
<a href="https://github.com/tanstack/virtual" target="\_parent">
<img alt="github stars" src="https://img.shields.io/github/stars/tanstack/virtual.svg?style=social&label=Star" />
</a>
<a href="https://bundlephobia.com/result?p=@tanstack/virtual-core@latest" target="\_parent">
<img alt="bundle size" src="https://badgen.net/bundlephobia/minzip/@tanstack/virtual-core@latest" />
</a>
</div>
<div align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://bestofjs.org/projects/tanstack-virtual">
<img alt="Best of JS" src="https://img.shields.io/endpoint?url=https://bestofjs-serverless.now.sh/api/project-badge?fullName=TanStack%2Fvirtual%26since=daily" alt="Best of JS"/>
</a>
<a href="https://twitter.com/tan_stack">
<img src="https://img.shields.io/twitter/follow/tan_stack.svg?style=social" alt="Follow @TanStack"/>
</a>
</div>
<div align="center">
### [Become a Sponsor!](https://github.com/sponsors/tannerlinsley/)
</div>
# TanStack Virtual
A headless, framework‑agnostic virtualization library for rendering massive lists, grids, and tables at 60FPS while giving you full control over markup and styles.
- Framework‑agnostic & headless
- Virtualizes vertical, horizontal & grid layouts with a single hook/function
- Lightweight (10–15kb) yet powerful, with dynamic & measured sizing support
- Smooth 60FPS scrolling with sticky items and window‑scrolling utilities
### <a href="https://tanstack.com/virtual" >Read the docs →</a>
## Get Involved
- We welcome issues and pull requests!
- Participate in [GitHub discussions](https://github.com/TanStack/virtual/discussions)
- Chat with the community on [Discord](https://discord.com/invite/WrRKjPJ)
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions
## Partners
<table align="center">
<tr>
<td>
<a href="https://www.coderabbit.ai/?via=tanstack&dub_id=aCcEEdAOqqutX6OS">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/coderabbit-dark-CMcuvjEy.svg" height="40" />
<source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/coderabbit-light-DVMJ2jHi.svg" height="40" />
<img src="https://tanstack.com/assets/coderabbit-light-DVMJ2jHi.svg" height="40" alt="CodeRabbit" />
</picture>
</a>
</td>
<td padding="20">
<a href="https://www.cloudflare.com?utm_source=tanstack">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/cloudflare-white-DQDB7UaL.svg" height="60" />
<source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/cloudflare-black-CPufaW0B.svg" height="60" />
<img src="https://tanstack.com/assets/cloudflare-black-CPufaW0B.svg" height="60" alt="Cloudflare" />
</picture>
</a>
</td>
</tr>
</table>
<div align="center">
<img src="./media/partner_logo.svg" alt="Virtual & you?" height="65">
<p>
We're looking for TanStack Virtual Partners to join our mission! Partner with us to push the boundaries of TanStack Virtual and build amazing things together.
</p>
<a href="mailto:partners@tanstack.com?subject=TanStack Virtual Partnership"><b>LET'S CHAT</b></a>
</div>
## Explore the TanStack Ecosystem
- <a href="https://github.com/tanstack/config"><b>TanStack Config</b></a> – Tooling for JS/TS packages
- <a href="https://github.com/tanstack/db"><b>TanStack DB</b></a> – Reactive sync client store
- <a href="https://github.com/tanstack/devtools"><b>TanStack DevTools</b></a> – Unified devtools panel
- <a href="https://github.com/tanstack/form"><b>TanStack Form</b></a> – Type‑safe form state
- <a href="https://github.com/tanstack/pacer"><b>TanStack Pacer</b></a> – Debouncing, throttling, batching <br/>
- <a href="https://github.com/tanstack/query"><b>TanStack Query</b></a> – Async state & caching
- <a href="https://github.com/tanstack/ranger"><b>TanStack Ranger</b></a> – Range & slider primitives
- <a href="https://github.com/tanstack/router"><b>TanStack Router</b></a> – Type‑safe routing, caching & URL state
- <a href="https://github.com/tanstack/router"><b>TanStack Start</b></a> – Full‑stack SSR & streaming
- <a href="https://github.com/tanstack/store"><b>TanStack Store</b></a> – Reactive data store
- <a href="https://github.com/tanstack/table"><b>TanStack Table</b></a> – Headless datagrids
… and more at <a href="https://tanstack.com"><b>TanStack.com »</b></a>
<!-- Use the force, Luke -->
================================================
FILE: docs/api/virtual-item.md
================================================
---
title: VirtualItem
---
The `VirtualItem` object represents a single item returned by the virtualizer. It contains information you need to render the item in the coordinate space within your virtualizer's scrollElement and other helpful properties/functions.
```tsx
export interface VirtualItem {
key: string | number | bigint
index: number
start: number
end: number
size: number
}
```
The following properties and methods are available on each VirtualItem object:
### `key`
```tsx
key: string | number | bigint
```
The unique key for the item. By default this is the item index, but should be configured via the `getItemKey` Virtualizer option.
### `index`
```tsx
index: number
```
The index of the item.
### `start`
```tsx
start: number
```
The starting pixel offset for the item. This is usually mapped to a css property or transform like `top/left` or `translateX/translateY`.
### `end`
```tsx
end: number
```
The ending pixel offset for the item. This value is not necessary for most layouts, but can be helpful so we've provided it anyway.
### `size`
```tsx
size: number
```
The size of the item. This is usually mapped to a css property like `width/height`. Before an item is measured with the `VirtualItem.measureElement` method, this will be the estimated size returned from your `estimateSize` virtualizer option. After an item is measured (if you choose to measure it at all), this value will be the number returned by your `measureElement` virtualizer option (which by default is configured to measure elements with `getBoundingClientRect()`).
### `lane`
```tsx
lane: number
```
The lane index of the item. In regular lists it will always be set to `0` but becomes useful for masonry layouts (see variable examples for more details).
================================================
FILE: docs/api/virtualizer.md
================================================
---
title: Virtualizer
---
The `Virtualizer` class is the core of TanStack Virtual. Virtualizer instances are usually created for you by your framework adapter, but you do receive the virtualizer directly.
```tsx
export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
constructor(options: VirtualizerOptions<TScrollElement, TItemElement>)
}
```
## Required Options
### `count`
```tsx
count: number
```
The total number of items to virtualize.
### `getScrollElement`
```tsx
getScrollElement: () => TScrollElement
```
A function that returns the scrollable element for the virtualizer. It may return null if the element is not available yet.
### `estimateSize`
```tsx
estimateSize: (index: number) => number
```
> 🧠 If you are dynamically measuring your elements, it's recommended to estimate the largest possible size (width/height, within comfort) of your items. This will help the virtualizer calculate more accurate initial positions.
This function is passed the index of each item and should return the actual size (or estimated size if you will be dynamically measuring items with `virtualItem.measureElement`) for each item. This measurement should return either the width or height depending on the orientation of your virtualizer.
## Optional Options
### `enabled`
```tsx
enabled?: boolean
```
Set to `false` to disable scrollElement observers and reset the virtualizer's state
### `debug`
```tsx
debug?: boolean
```
Set to `true` to enable debug logs
### `initialRect`
```tsx
initialRect?: Rect
```
The initial `Rect` of the scrollElement. This is mostly useful if you need to run the virtualizer in an SSR environment, otherwise the initialRect will be calculated on mount by the `observeElementRect` implementation.
### `onChange`
```tsx
onChange?: (instance: Virtualizer<TScrollElement, TItemElement>, sync: boolean) => void
```
A callback function that fires when the virtualizer's internal state changes. It's passed the virtualizer instance and the sync parameter.
The sync parameter indicates whether scrolling is currently in progress. It is `true` when scrolling is ongoing, and `false` when scrolling has stopped or other actions (such as resizing) are being performed.
### `overscan`
```tsx
overscan?: number
```
The number of items to render above and below the visible area. Increasing this number will increase the amount of time it takes to render the virtualizer, but might decrease the likelihood of seeing slow-rendering blank items at the top and bottom of the virtualizer when scrolling. The default value is `1`.
### `horizontal`
```tsx
horizontal?: boolean
```
Set this to `true` if your virtualizer is oriented horizontally.
### `paddingStart`
```tsx
paddingStart?: number
```
The padding to apply to the start of the virtualizer in pixels.
### `paddingEnd`
```tsx
paddingEnd?: number
```
The padding to apply to the end of the virtualizer in pixels.
### `scrollPaddingStart`
```tsx
scrollPaddingStart?: number
```
The padding to apply to the start of the virtualizer in pixels when scrolling to an element.
### `scrollPaddingEnd`
```tsx
scrollPaddingEnd?: number
```
The padding to apply to the end of the virtualizer in pixels when scrolling to an element.
### `initialOffset`
```tsx
initialOffset?: number | (() => number)
```
The position where the list is scrolled to on render. This is useful if you are rendering the virtualizer in a SSR environment or are conditionally rendering the virtualizer.
### `getItemKey`
```tsx
getItemKey?: (index: number) => Key
```
This function is passed the index of each item and should return a unique key for that item. The default functionality of this function is to return the index of the item, but you should override this when possible to return a unique identifier for each item across the entire set.
**Note:** The virtualizer automatically invalidates its measurement cache when measurement-affecting options change, ensuring `getTotalSize()` and other measurements return fresh values. While the virtualizer intelligently tracks which options actually affect measurements, it's still better to memoize `getItemKey` (e.g., using `useCallback` in React) to avoid unnecessary recalculations.
### `rangeExtractor`
```tsx
rangeExtractor?: (range: Range) => number[]
```
This function receives visible range indexes and should return array of indexes to render. This is useful if you need to add or remove items from the virtualizer manually regardless of the visible range, eg. rendering sticky items, headers, footers, etc. The default range extractor implementation will return the visible range indexes and is exported as `defaultRangeExtractor`.
### `scrollToFn`
```tsx
scrollToFn?: (
offset: number,
options: { adjustments?: number; behavior?: 'auto' | 'smooth' },
instance: Virtualizer<TScrollElement, TItemElement>,
) => void
```
An optional function that (if provided) should implement the scrolling behavior for your scrollElement. It will be called with the following arguments:
- An `offset` (in pixels) to scroll towards.
- An object indicating whether there was a difference between the estimated size and actual size (`adjustments`) and/or whether scrolling was called with a smooth animation (`behaviour`).
- The virtualizer instance itself.
Note that built-in scroll implementations are exported as `elementScroll` and `windowScroll`, which are automatically configured by the framework adapter functions like `useVirtualizer` or `useWindowVirtualizer`.
### `observeElementRect`
```tsx
observeElementRect: (
instance: Virtualizer<TScrollElement, TItemElement>,
cb: (rect: Rect) => void,
) => void | (() => void)
```
An optional function that if provided is called when the scrollElement changes and should implement the initial measurement and continuous monitoring of the scrollElement's `Rect` (an object with `width` and `height`). It's called with the instance (which also gives you access to the scrollElement via `instance.scrollElement`. Built-in implementations are exported as `observeElementRect` and `observeWindowRect` which are automatically configured for you by your framework adapter's exported functions like `useVirtualizer` or `useWindowVirtualizer`.
### `observeElementOffset`
```tsx
observeElementOffset: (
instance: Virtualizer<TScrollElement, TItemElement>,
cb: (offset: number) => void,
) => void | (() => void)
```
An optional function that if provided is called when the scrollElement changes and should implement the initial measurement and continuous monitoring of the scrollElement's scroll offset (a number). It's called with the instance (which also gives you access to the scrollElement via `instance.scrollElement`. Built-in implementations are exported as `observeElementOffset` and `observeWindowOffset` which are automatically configured for you by your framework adapter's exported functions like `useVirtualizer` or `useWindowVirtualizer`.
### `measureElement`
```tsx
measureElement?: (
element: TItemElement,
entry: ResizeObserverEntry | undefined,
instance: Virtualizer<TScrollElement, TItemElement>,
) => number
```
This optional function is called when the virtualizer needs to dynamically measure the size (width or height) of an item.
> 🧠 You can use `instance.options.horizontal` to determine if the width or height of the item should be measured.
### `scrollMargin`
```tsx
scrollMargin?: number
```
With this option, you can specify where the scroll offset should originate. Typically, this value represents the space between the beginning of the scrolling element and the start of the list. This is especially useful in common scenarios such as when you have a header preceding a window virtualizer or when multiple virtualizers are utilized within a single scrolling element. If you are using absolute positioning of elements, you should take into account the `scrollMargin` in your CSS transform:
```tsx
transform: `translateY(${
virtualRow.start - rowVirtualizer.options.scrollMargin
}px)`
```
To dynamically measure value for `scrollMargin` you can use `getBoundingClientRect()` or ResizeObserver. This is helpful in scenarios when items above your virtual list might change their height.
### `gap`
```tsx
gap?: number
```
This option allows you to set the spacing between items in the virtualized list. It's particularly useful for maintaining a consistent visual separation between items without having to manually adjust each item's margin or padding. The value is specified in pixels.
### `lanes`
```tsx
lanes: number
```
The number of lanes the list is divided into (aka columns for vertical lists and rows for horizontal lists).
### `isScrollingResetDelay`
```tsx
isScrollingResetDelay: number
```
This option allows you to specify the duration to wait after the last scroll event before resetting the isScrolling instance property. The default value is 150 milliseconds.
The implementation of this option is driven by the need for a reliable mechanism to handle scrolling behavior across different browsers. Until all browsers uniformly support the scrollEnd event.
### `useScrollendEvent`
```tsx
useScrollendEvent: boolean
```
Determines whether to use the native scrollend event to detect when scrolling has stopped. If set to false, a debounced fallback is used to reset the isScrolling instance property after isScrollingResetDelay milliseconds. The default value is `false`.
The implementation of this option is driven by the need for a reliable mechanism to handle scrolling behavior across different browsers. Until all browsers uniformly support the scrollEnd event.
### `isRtl`
```tsx
isRtl: boolean
```
Whether to invert horizontal scrolling to support right-to-left language locales.
### `useAnimationFrameWithResizeObserver`
```tsx
useAnimationFrameWithResizeObserver: boolean
```
**Default:** `false`
When enabled, defers ResizeObserver measurement processing to the next animation frame using `requestAnimationFrame`.
**Important:** This option typically **should not be enabled** in most cases. ResizeObserver callbacks already execute at an optimal time in the browser's rendering pipeline (after layout, before paint), and the measurements provided in the callback are pre-computed by the browser without causing additional reflows.
**Potential use cases:**
- If you're performing heavy DOM mutations in response to size changes and want to batch them with the next render cycle
- As a workaround for the "ResizeObserver loop completed with undelivered notifications" error (though this usually indicates a deeper issue that should be fixed)
**Tradeoffs:**
- **Adds ~16ms delay:** Measurements are deferred to the next frame, which can cause visual artifacts, stale measurements, or slower time-to-interactive
- **No batching benefit:** ResizeObserver already batches multiple element resizes into a single callback
- **Defeats optimization:** The browser has already computed the measurements synchronously; deferring them provides no performance benefit for reading values
Only enable this option if you have a specific reason and have measured that it improves your use case.
## Virtualizer Instance
The following properties and methods are available on the virtualizer instance:
### `options`
```tsx
options: readonly Required<VirtualizerOptions<TScrollElement, TItemElement>>
```
The current options for the virtualizer. This property is updated via your framework adapter and is read-only.
### `scrollElement`
```tsx
scrollElement: readonly TScrollElement | null
```
The current scrollElement for the virtualizer. This property is updated via your framework adapter and is read-only.
### `getVirtualItems`
```tsx
type getVirtualItems = () => VirtualItem[]
```
Returns the virtual items for the current state of the virtualizer.
### `getVirtualIndexes`
```tsx
type getVirtualIndexes = () => number[]
```
Returns the virtual row indexes for the current state of the virtualizer.
### `scrollToOffset`
```tsx
scrollToOffset: (
toOffset: number,
options?: {
align?: 'start' | 'center' | 'end' | 'auto',
behavior?: 'auto' | 'smooth'
}
) => void
```
Scrolls the virtualizer to the pixel offset provided. You can optionally pass an alignment mode to anchor the scroll to a specific part of the scrollElement.
### `scrollToIndex`
```tsx
scrollToIndex: (
index: number,
options?: {
align?: 'start' | 'center' | 'end' | 'auto',
behavior?: 'auto' | 'smooth'
}
) => void
```
Scrolls the virtualizer to the items of the index provided. You can optionally pass an alignment mode to anchor the scroll to a specific part of the scrollElement.
> 🧠 During smooth scrolling, the virtualizer only measures items within a buffer range around the scroll target. Items far from the target are skipped to prevent their size changes from shifting the target position and breaking the smooth animation.
>
> Because of this, the preferred layout strategy for smooth scrolling is **block translation** — translate the entire rendered block using the first item's `start` offset, rather than positioning each item independently with absolute positioning. This ensures items stay correctly positioned relative to each other even when some measurements are skipped.
### `scrollBy`
```tsx
scrollBy: (
delta: number,
options?: {
behavior?: 'auto' | 'smooth'
}
) => void
```
Scrolls the virtualizer by the specified number of pixels relative to the current scroll position.
### `getTotalSize`
```tsx
getTotalSize: () => number
```
Returns the total size in pixels for the virtualized items. This measurement will incrementally change if you choose to dynamically measure your elements as they are rendered.
### `measure`
```tsx
measure: () => void
```
Resets any prev item measurements.
### `measureElement`
```tsx
measureElement: (el: TItemElement | null) => void
```
Measures the element using your configured `measureElement` virtualizer option. You are responsible for calling this in your virtualizer markup when the component is rendered (eg. using something like React's ref callback prop) also adding `data-index`
```tsx
<div
key={virtualRow.key}
data-index={virtualRow.index}
ref={virtualizer.measureElement}
style={...}
>...</div>
```
By default the `measureElement` virtualizer option is configured to measure elements with `getBoundingClientRect()`.
### `resizeItem`
```tsx
resizeItem: (index: number, size: number) => void
```
Change the virtualized item's size manually. Use this function to manually set the size calculated for this index. Useful in occations when using some custom morphing transition and you know the morphed item's size beforehand.
You can also use this method with a throttled ResizeObserver instead of `Virtualizer.measureElement` to reduce re-rendering.
> ⚠️ Please be aware that manually changing the size of an item when using `Virtualizer.measureElement` to monitor that item, will result in unpredictable behaviour as the `Virtualizer.measureElement` is also changing the size. However you can use one of resizeItem or measureElement in the same virtualizer instance but on different item indexes.
### `scrollRect`
```tsx
scrollRect: Rect
```
Current `Rect` of the scroll element.
### `shouldAdjustScrollPositionOnItemSizeChange`
```tsx
shouldAdjustScrollPositionOnItemSizeChange: undefined | ((item: VirtualItem, delta: number, instance: Virtualizer<TScrollElement, TItemElement>) => boolean)
```
The shouldAdjustScrollPositionOnItemSizeChange method enables fine-grained control over the adjustment of scroll position when the size of dynamically rendered items differs from the estimated size. When jumping in the middle of the list and scrolling backward new elements may have a different size than the initially estimated size. This discrepancy can cause subsequent items to shift, potentially disrupting the user's scrolling experience, particularly when navigating backward through the list.
### `isScrolling`
```tsx
isScrolling: boolean
```
Boolean flag indicating if list is currently being scrolled.
### `scrollDirection`
```tsx
scrollDirection: 'forward' | 'backward' | null
```
This option indicates the direction of scrolling, with possible values being 'forward' for scrolling downwards and 'backward' for scrolling upwards. The value is set to null when there is no active scrolling.
### `scrollOffset`
```tsx
scrollOffset: number
```
This option represents the current scroll position along the scrolling axis. It is measured in pixels from the starting point of the scrollable area.
================================================
FILE: docs/config.json
================================================
{
"$schema": "https://raw.githubusercontent.com/TanStack/tanstack.com/main/tanstack-docs-config.schema.json",
"docSearch": {
"appId": "",
"indexName": "",
"apiKey": ""
},
"sections": [
{
"label": "Getting Started",
"children": [
{ "label": "Introduction", "to": "introduction" },
{ "label": "Installation", "to": "installation" }
],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "React Virtual",
"to": "framework/react/react-virtual"
}
]
},
{
"label": "angular",
"children": [
{
"label": "Angular Virtual",
"to": "framework/angular/angular-virtual"
}
]
},
{
"label": "solid",
"children": [
{ "label": "Solid Virtual", "to": "framework/solid/solid-virtual" }
]
},
{
"label": "svelte",
"children": [
{
"label": "Svelte Virtual",
"to": "framework/svelte/svelte-virtual"
}
]
},
{
"label": "vue",
"children": [
{
"label": "Vue Virtual",
"to": "framework/vue/vue-virtual"
}
]
}
]
},
{
"label": "Core APIs",
"children": [
{ "label": "Virtualizer", "to": "api/virtualizer" },
{ "label": "VirtualItem", "to": "api/virtual-item" }
]
},
{
"label": "Examples",
"children": [],
"frameworks": [
{
"label": "angular",
"children": [
{
"to": "framework/angular/examples/fixed",
"label": "Fixed"
},
{
"to": "framework/angular/examples/variable",
"label": "Variable"
},
{
"to": "framework/angular/examples/dynamic",
"label": "Dynamic"
},
{
"to": "framework/angular/examples/padding",
"label": "Padding"
},
{
"to": "framework/angular/examples/sticky",
"label": "Sticky"
},
{
"to": "framework/angular/examples/infinite-scroll",
"label": "Infinite Scroll"
},
{
"to": "framework/angular/examples/smooth-scroll",
"label": "Smooth Scroll"
},
{
"to": "framework/angular/examples/table",
"label": "Table"
},
{
"to": "framework/angular/examples/window",
"label": "Window"
}
]
},
{
"label": "react",
"children": [
{
"to": "framework/react/examples/fixed",
"label": "Fixed"
},
{
"to": "framework/react/examples/variable",
"label": "Variable"
},
{
"to": "framework/react/examples/dynamic",
"label": "Dynamic"
},
{
"to": "framework/react/examples/padding",
"label": "Padding"
},
{
"to": "framework/react/examples/sticky",
"label": "Sticky"
},
{
"to": "framework/react/examples/infinite-scroll",
"label": "Infinite Scroll"
},
{
"to": "framework/react/examples/smooth-scroll",
"label": "Smooth Scroll"
},
{
"to": "framework/react/examples/table",
"label": "Table"
},
{
"to": "framework/react/examples/window",
"label": "Window"
}
]
},
{
"label": "svelte",
"children": [
{
"to": "framework/svelte/examples/fixed",
"label": "Fixed"
},
{
"to": "framework/svelte/examples/variable",
"label": "Variable"
},
{
"to": "framework/svelte/examples/dynamic",
"label": "Dynamic"
},
{
"to": "framework/svelte/examples/sticky",
"label": "Sticky"
},
{
"to": "framework/svelte/examples/infinite-scroll",
"label": "Infinite Scroll"
},
{
"to": "framework/svelte/examples/smooth-scroll",
"label": "Smooth Scroll"
},
{
"to": "framework/svelte/examples/table",
"label": "Table"
}
]
},
{
"label": "vue",
"children": [
{
"to": "framework/vue/examples/fixed",
"label": "Fixed"
},
{
"to": "framework/vue/examples/variable",
"label": "Variable"
},
{
"to": "framework/vue/examples/dynamic",
"label": "Dynamic"
},
{
"to": "framework/vue/examples/sticky",
"label": "Sticky"
},
{
"to": "framework/vue/examples/infinite-scroll",
"label": "Infinite Scroll"
},
{
"to": "framework/vue/examples/smooth-scroll",
"label": "Smooth Scroll"
},
{
"to": "framework/vue/examples/table",
"label": "Table"
},
{
"to": "framework/vue/examples/padding",
"label": "Padding"
},
{
"to": "framework/vue/examples/scroll-padding",
"label": "Scroll Padding"
}
]
},
{
"label": "lit",
"children": [
{
"to": "framework/lit/examples/fixed",
"label": "Fixed"
},
{
"to": "framework/lit/examples/dynamic",
"label": "Dynamic"
}
]
}
]
}
]
}
================================================
FILE: docs/framework/angular/angular-virtual.md
================================================
---
title: Angular Virtual
---
The `@tanstack/angular-virtual` adapter is a wrapper around the core virtual logic.
## `injectVirtualizer`
```ts
function injectVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
Omit<VirtualizerOptions<TScrollElement, TItemElement>, 'getScrollElement'>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
> & { scrollElement: ElementRef<TScrollElement> | TScrollElement | undefined },
): AngularVirtualizer<TScrollElement, TItemElement>
```
This function returns an `AngularVirtualizer` instance configured to work with an HTML element as the scrollElement.
## `injectWindowVirtualizer`
```ts
function injectWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): AngularVirtualizer<Window, TItemElement>
```
This function returns a window-based `AngularVirtualizer` instance configured to work with the window as the scrollElement.
================================================
FILE: docs/framework/lit/lit-virtual.md
================================================
---
title: Lit Virtual
---
The `@tanstack/lit-virtual` adapter is a wrapper around the core virtual logic.
## `createVirtualizer`
```tsx
private virtualizerController = new VirtualizerController<TScrollElement, TItemElement = unknown>(
options: PartialKeys< VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
)
```
This class stands for a standard `Virtualizer` instance configured to work with an HTML element as the scrollElement.
This will create a Lit Controller which can be accessed in the element render method.
```tsx
render() {
const virtualizer = this.virtualizerController.getVirtualizer();
const virtualItems = virtualizer.getVirtualItems();
}
)
```
## `createWindowVirtualizer`
```tsx
private windowVirtualizerController = new WindowVirtualizerController<TItemElement = unknown>(
options: PartialKeys< VirtualizerOptions<TItemElement>,
'getScrollElement' | 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
```
This class stands of window-based `Virtualizer` instance configured to work with an HTML element as the scrollElement.
================================================
FILE: docs/framework/react/react-virtual.md
================================================
---
title: React Virtual
---
The `@tanstack/react-virtual` adapter is a wrapper around the core virtual logic.
## `useVirtualizer`
```tsx
function useVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
ReactVirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
): Virtualizer<TScrollElement, TItemElement>
```
This function returns a standard `Virtualizer` instance configured to work with an HTML element as the scrollElement.
## `useWindowVirtualizer`
```tsx
function useWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
ReactVirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): Virtualizer<Window, TItemElement>
```
This function returns a window-based `Virtualizer` instance configured to work with the window as the scrollElement.
## React-Specific Options
### `useFlushSync`
```tsx
type ReactVirtualizerOptions<TScrollElement, TItemElement> =
VirtualizerOptions<TScrollElement, TItemElement> & {
useFlushSync?: boolean
}
```
Both `useVirtualizer` and `useWindowVirtualizer` accept a `useFlushSync` option that controls whether React's `flushSync` is used for synchronous updates.
- **Type**: `boolean`
- **Default**: `true`
- **Description**: When `true`, the virtualizer will use `flushSync` from `react-dom` to ensure synchronous rendering during scroll events. This provides the most accurate scrolling behavior but may impact performance in some scenarios.
#### When to disable `useFlushSync`
You may want to set `useFlushSync: false` in the following scenarios:
- **React 19 compatibility**: In React 19, you may see the following console warning when scrolling:
```
flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task.
```
Setting `useFlushSync: false` will eliminate this warning by allowing React to batch updates naturally.
- **Performance optimization**: If you experience performance issues with rapid scrolling on lower-end devices
- **Testing environments**: When running tests that don't require synchronous DOM updates
- **Non-critical lists**: When slight visual delays during scrolling are acceptable for better overall performance
#### Example
```tsx
const virtualizer = useVirtualizer({
count: 10000,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
useFlushSync: false, // Disable synchronous updates
})
```
================================================
FILE: docs/framework/solid/solid-virtual.md
================================================
---
title: Solid Virtual
---
The `@tanstack/solid-virtual` adapter is a wrapper around the core virtual logic.
## `createVirtualizer`
```tsx
function createVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
): Virtualizer<TScrollElement, TItemElement>
```
This function returns a standard `Virtualizer` instance configured to work with an HTML element as the scrollElement.
## `createWindowVirtualizer`
```tsx
function createWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): Virtualizer<Window, TItemElement>
```
This function returns a window-based `Virtualizer` instance configured to work with the window as the scrollElement.
================================================
FILE: docs/framework/svelte/svelte-virtual.md
================================================
---
title: Svelte Virtual
---
The `@tanstack/svelte-virtual` adapter is a wrapper around the core virtual logic.
## `createVirtualizer`
```tsx
function createVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
): Virtualizer<TScrollElement, TItemElement>
```
This function returns a standard `Virtualizer` instance configured to work with an HTML element as the scrollElement.
## `createWindowVirtualizer`
```tsx
function createWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): Virtualizer<Window, TItemElement>
```
This function returns a window-based `Virtualizer` instance configured to work with the window as the scrollElement.
================================================
FILE: docs/framework/vue/vue-virtual.md
================================================
---
title: Vue Virtual
---
The `@tanstack/vue-virtual` adapter is a wrapper around the core virtual logic.
## `useVirtualizer`
```tsx
function useVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
): Virtualizer<TScrollElement, TItemElement>
```
This function returns a standard `Virtualizer` instance configured to work with an HTML element as the scrollElement.
## `useWindowVirtualizer`
```tsx
function useWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): Virtualizer<Window, TItemElement>
```
This function returns a window-based `Virtualizer` instance configured to work with the window as the scrollElement.
================================================
FILE: docs/installation.md
================================================
---
title: Installation
---
Before we dig in to the API, let's get you set up!
Install your TanStack Virtual adapter as a dependency using your favorite npm package manager
## React Virtual
```bash
npm install @tanstack/react-virtual
```
## Solid Virtual
```bash
npm install @tanstack/solid-virtual
```
## Svelte Virtual
```bash
npm install @tanstack/svelte-virtual
```
## Vue Virtual
```bash
npm install @tanstack/vue-virtual
```
## Lit Virtual
```bash
npm install @tanstack/lit-virtual
```
## Angular Virtual
```bash
npm install @tanstack/angular-virtual
```
## Virtual Core (no framework)
```bash
npm install @tanstack/virtual-core
```
================================================
FILE: docs/introduction.md
================================================
---
title: Introduction
---
TanStack Virtual is a headless UI utility for virtualizing long lists of elements in JS/TS, React, Vue, Svelte, Solid, Lit, and Angular. It is not a component therefore does not ship with or render any markup or styles for you. While this requires a bit of markup and styles from you, you will retain 100% control over your styles, design and implementation.
## The Virtualizer
At the heart of TanStack Virtual is the `Virtualizer`. Virtualizers can be oriented on either the vertical (default) or horizontal axes which makes it possible to achieve vertical, horizontal and even grid-like virtualization by combining the two axis configurations together.
Here is just a quick example of what it looks like to virtualize a long list within a div using TanStack Virtual in React:
```tsx
import { useVirtualizer } from '@tanstack/react-virtual';
function App() {
// The scrollable element for your list
const parentRef = React.useRef(null)
// The virtualizer
const rowVirtualizer = useVirtualizer({
count: 10000,
getScrollElement: () => parentRef.current,
estimateSize: () => 35,
})
return (
<>
{/* The scrollable element for your list */}
<div
ref={parentRef}
style={{
height: `400px`,
overflow: 'auto', // Make it scroll!
}}
>
{/* The large inner element to hold all of the items */}
<div
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{/* Only the visible items in the virtualizer, manually positioned to be in view */}
{rowVirtualizer.getVirtualItems().map((virtualItem) => (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
>
Row {virtualItem.index}
</div>
))}
</div>
</div>
</>
)
}
```
Let's dig into some more examples!
================================================
FILE: eslint.config.js
================================================
// @ts-check
import { tanstackConfig } from '@tanstack/eslint-config'
export default [
...tanstackConfig,
{
name: 'tanstack/temp',
rules: {
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/no-unsafe-function-type': 'off',
'no-self-assign': 'off',
},
},
]
================================================
FILE: examples/angular/dynamic/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/dynamic/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/dynamic/README.md
================================================
# @tanstack/virtualExampleAngularDynamic
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/dynamic/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"newProjectRoot": "projects",
"projects": {
"@tanstack/virtual-example-angular-dynamic": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-dynamic",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-dynamic:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-dynamic:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-dynamic:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/dynamic/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-dynamic",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@faker-js/faker": "^8.4.1",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/dynamic/src/app/app.component.ts
================================================
import { Component } from '@angular/core'
import { RouterLink, RouterOutlet } from '@angular/router'
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterLink, RouterOutlet],
template: `
<p>
These components are using <strong>dynamic</strong> sizes. This means that
each element's exact dimensions are unknown when rendered. An estimated
dimension is used to get an a initial measurement, then this measurement
is readjusted on the fly as each element is rendered.
</p>
<ul>
<li><a routerLink="./">List</a></li>
<li><a routerLink="./window-list">List - window as scroller</a></li>
<li><a routerLink="./columns">Column</a></li>
<li><a routerLink="./grid">Grid</a></li>
</ul>
<router-outlet />
`,
styles: [],
})
export class AppComponent {}
================================================
FILE: examples/angular/dynamic/src/app/app.config.ts
================================================
import { ApplicationConfig } from '@angular/core'
import { provideRouter } from '@angular/router'
import { routes } from './app.routes'
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes)],
}
================================================
FILE: examples/angular/dynamic/src/app/app.routes.ts
================================================
import { Routes } from '@angular/router'
import { RowVirtualizerDynamic } from './row-virtualizer-dynamic.component'
import { GridVirtualizerDynamic } from './grid-virtualizer-dynamic.component'
import { ColumnVirtualizerDynamic } from './column-virtualizer-dynamic.component'
import { RowVirtualizerDynamicWindow } from './row-virtualizer-dynamic-window.component'
export const routes: Routes = [
{
path: '',
component: RowVirtualizerDynamic,
},
{
path: 'window-list',
component: RowVirtualizerDynamicWindow,
},
{
path: 'columns',
component: ColumnVirtualizerDynamic,
},
{
path: 'grid',
component: GridVirtualizerDynamic,
},
]
================================================
FILE: examples/angular/dynamic/src/app/column-virtualizer-dynamic.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
effect,
viewChild,
viewChildren,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
import { sentences } from './utils'
@Component({
standalone: true,
selector: 'column-virtualizer-dynamic',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Columns</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="virtualizer.getTotalSize()"
>
@for (col of virtualizer.getVirtualItems(); track col.index) {
<div
#virtualItem
[attr.data-index]="col.index"
[class.list-item-even]="col.index % 2 === 0"
[class.list-item-odd]="col.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; height: 100%;"
[style.width.px]="sentences[col.index].length"
[style.transform]="'translateX(' + col.start + 'px)'"
>
<div>
<div>Column {{ col.index }}</div>
<div>{{ sentences[col.index] }}</div>
</div>
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 400px;
width: 400px;
overflow: auto;
}
`,
})
export class ColumnVirtualizerDynamic {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
sentences = sentences
count = this.sentences.length
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.virtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
virtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: this.count,
estimateSize: () => 100,
overscan: 5,
}))
}
================================================
FILE: examples/angular/dynamic/src/app/grid-virtualizer-dynamic.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
afterNextRender,
computed,
effect,
signal,
viewChild,
viewChildren,
} from '@angular/core'
import {
injectVirtualizer,
injectWindowVirtualizer,
} from '@tanstack/angular-virtual'
import { generateColumns, generateData } from './utils'
@Component({
standalone: true,
selector: 'grid-virtualizer-dynamic',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Grid</h3>
<div
#scrollElement
class="list scroll-container"
style="border: 1px solid #c8c8c8"
>
<div
style="position: relative;"
[style.height.px]="rowVirtualizer.getTotalSize()"
>
@for (row of rowVirtualizer.getVirtualItems(); track row.key) {
<div
[attr.data-index]="row.index"
#virtualRow
style="position: absolute; top: 0; left: 0; display: flex;"
[style.transform]="
'translateY(' +
(row.start - rowVirtualizer.options().scrollMargin) +
'px)'
"
>
<div [style.width.px]="width()[0]"></div>
@for (col of columnVirtualizer.getVirtualItems(); track col.key) {
<div
style="border-bottom: 1px solid #c8c8c8; border-right: 1px solid #c8c8c8; padding: 7px 12px"
[style.minHeight.px]="row.index === 0 ? 50 : row.size"
[style.width.px]="getColumnWidth(col.index)"
>
<div>
{{
row.index === 0
? columns[col.index].name
: data[row.index][col.index]
}}
</div>
</div>
}
<div [style.width.px]="width()[1]"></div>
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
overflow: auto;
}
`,
})
export class GridVirtualizerDynamic {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
columns = generateColumns(30)
data = generateData(this.columns)
parentOffset = signal(0)
constructor() {
afterNextRender(() =>
this.parentOffset.set(this.scrollElement()!.nativeElement.offsetTop),
)
}
getColumnWidth = (index: number) => this.columns[index].width
rowVirtualizer = injectWindowVirtualizer(() => ({
count: this.data.length,
estimateSize: () => 350,
overscan: 5,
scrollMargin: this.parentOffset(),
}))
columnVirtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: this.columns.length,
estimateSize: this.getColumnWidth,
overscan: 5,
}))
width = computed(
() => {
const virtualColumns = this.columnVirtualizer.getVirtualItems()
return virtualColumns.length > 0
? [
virtualColumns[0].start,
this.columnVirtualizer.getTotalSize() -
virtualColumns[virtualColumns.length - 1].end,
]
: [0, 0]
},
{ equal: (a, b) => a[0] === b[0] && a[1] === b[1] },
)
virtualRows = viewChildren<ElementRef<HTMLDivElement>>('virtualRow')
#measureItems = effect(
() =>
this.virtualRows().forEach((el) => {
this.rowVirtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
}
================================================
FILE: examples/angular/dynamic/src/app/row-virtualizer-dynamic-window.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
afterNextRender,
effect,
signal,
untracked,
viewChild,
viewChildren,
} from '@angular/core'
import { injectWindowVirtualizer } from '@tanstack/angular-virtual'
import { sentences } from './utils'
@Component({
standalone: true,
selector: 'row-virtualizer-dynamic',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div #scrollElement>
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
<div
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.transform]="
'translateY(' +
(virtualizer.getVirtualItems()[0]
? virtualizer.getVirtualItems()[0].start - parentOffset()
: 0) +
'px)'
"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
#virtualItem
[attr.data-index]="row.index"
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
>
<div style="padding: 10px 0">
<div>Row {{ row.index }}</div>
<div>{{ sentences[row.index] }}</div>
</div>
</div>
}
</div>
</div>
</div>
`,
styles: `
.scroll-container {
height: 400px;
width: 400px;
overflow-y: auto;
contain: 'strict';
}
`,
})
export class RowVirtualizerDynamicWindow {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
parentOffset = signal(0)
constructor() {
afterNextRender(() =>
this.parentOffset.set(this.scrollElement()!.nativeElement.offsetTop),
)
}
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
sentences = sentences
count = this.sentences.length
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.virtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
virtualizer = injectWindowVirtualizer(() => ({
count: this.count,
estimateSize: () => 150,
scrollMargin: this.parentOffset(),
}))
}
================================================
FILE: examples/angular/dynamic/src/app/row-virtualizer-dynamic.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
effect,
viewChild,
viewChildren,
} from '@angular/core'
import {
AngularVirtualizer,
injectVirtualizer,
} from '@tanstack/angular-virtual'
import { sentences } from './utils'
@Component({
standalone: true,
selector: 'row-virtualizer-dynamic',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Rows</h3>
<button type="button" (click)="virtualizer.scrollToIndex(0)">
scroll to the top
</button>
<button type="button" (click)="virtualizer.scrollToIndex(count / 2)">
scroll to the middle
</button>
<button type="button" (click)="virtualizer.scrollToIndex(count - 1)">
scroll to the end
</button>
<hr />
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
<div
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.transform]="
'translateY(' +
(virtualizer.getVirtualItems()[0]
? virtualizer.getVirtualItems()[0].start
: 0) +
'px)'
"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
#virtualItem
[attr.data-index]="row.index"
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
>
<div style="padding: 10px 0">
<div>Row {{ row.index }}</div>
<div>{{ sentences[row.index] }}</div>
</div>
</div>
}
</div>
</div>
</div>
`,
styles: `
.scroll-container {
height: 400px;
width: 400px;
overflow-y: auto;
contain: 'strict';
}
`,
})
export class RowVirtualizerDynamic {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
sentences = sentences
count = this.sentences.length
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.virtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.count,
estimateSize: () => 120,
}))
}
================================================
FILE: examples/angular/dynamic/src/app/utils.ts
================================================
import { faker } from '@faker-js/faker'
export const generateRandomNumber = (min: number, max: number) =>
faker.number.int({ min, max })
// 1000 because 10000 takes many seconds
export const sentences = new Array(1000)
.fill(true)
.map(() => faker.lorem.sentence(generateRandomNumber(20, 70)))
interface Column {
key: string
name: string
width: number
}
export const generateColumns = (count: number) => {
return new Array(count).fill(0).map((_, i) => {
const key: string = i.toString()
return {
key,
name: `Column ${i}`,
width: generateRandomNumber(75, 300),
}
})
}
export const generateData = (columns: Column[], count = 300) => {
return new Array(count).fill(0).map((_, rowIndex) =>
columns.reduce<string[]>((acc, _curr, colIndex) => {
// simulate dynamic size cells
const val = faker.lorem.lines(((rowIndex + colIndex) % 10) + 1)
acc.push(val)
return acc
}, []),
)
}
================================================
FILE: examples/angular/dynamic/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularDynamic</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/dynamic/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { appConfig } from './app/app.config'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err))
================================================
FILE: examples/angular/dynamic/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/dynamic/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/dynamic/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"],
"paths": {
"@angular/*": ["./node_modules/@angular/*"]
}
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/fixed/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/fixed/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/fixed/README.md
================================================
# @tanstack/virtualExampleAngularFixed
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/fixed/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-fixed": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-fixed",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-fixed:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-fixed:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-fixed:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/fixed/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-fixed",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/fixed/src/app/app.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { ColumnVirtualizerFixed } from './column-virtualizer-fixed.component'
import { GridVirtualizerFixed } from './grid-virtualizer-fixed.component'
import { RowVirtualizerFixed } from './row-virtualizer-fixed.component'
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ColumnVirtualizerFixed, GridVirtualizerFixed, RowVirtualizerFixed],
template: `
<p>
These components are using <strong>fixed</strong> sizes. This means that
every element's dimensions are hard-coded to the same value and never
change.
</p>
<row-virtualizer-fixed />
<column-virtualizer-fixed />
<grid-virtualizer-fixed />
`,
})
export class AppComponent {}
================================================
FILE: examples/angular/fixed/src/app/column-virtualizer-fixed.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'column-virtualizer-fixed',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Columns</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="virtualizer.getTotalSize()"
>
@for (col of virtualizer.getVirtualItems(); track col.index) {
<div
[attr.data-index]="col.index"
[class.list-item-even]="col.index % 2 === 0"
[class.list-item-odd]="col.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; height: 100%;"
[style.width.px]="col.size"
[style.transform]="'translateX(' + col.start + 'px)'"
>
Col {{ col.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 100px;
width: 400px;
overflow: auto;
}
`,
})
export class ColumnVirtualizerFixed {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: () => 100,
overscan: 5,
}))
}
================================================
FILE: examples/angular/fixed/src/app/grid-virtualizer-fixed.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'grid-virtualizer-fixed',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Grid</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="columnVirtualizer.getTotalSize()"
[style.height.px]="rowVirtualizer.getTotalSize()"
>
@for (
row of rowVirtualizer.getVirtualItems();
track row.index;
let rowEven = $even
) {
@for (
col of columnVirtualizer.getVirtualItems();
track col.index;
let colEven = $even
) {
<div
[attr.data-index]="col.index"
[class]="
col.index % 2
? row.index % 2 === 0
? 'list-item-odd'
: 'list-item-even'
: row.index % 2
? 'list-item-odd'
: 'list-item-even'
"
style="position: absolute; top: 0; left: 0;"
[style.height.px]="row.size"
[style.width.px]="col.size"
[style.transform]="
'translateX(' +
col.start +
'px)' +
'translateY(' +
row.start +
'px)'
"
>
Cell {{ row.index }}, {{ col.index }}
</div>
}
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 500px;
width: 500px;
overflow: auto;
}
`,
})
export class GridVirtualizerFixed {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
rowVirtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: () => 35,
overscan: 5,
}))
columnVirtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: () => 100,
overscan: 5,
}))
}
================================================
FILE: examples/angular/fixed/src/app/row-virtualizer-fixed.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'row-virtualizer-fixed',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Rows</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
[attr.data-index]="row.index"
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="row.size"
[style.transform]="'translateY(' + row.start + 'px)'"
>
Row {{ row.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 200px;
width: 400px;
overflow: auto;
}
`,
})
export class RowVirtualizerFixed {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: () => 35,
overscan: 5,
}))
}
================================================
FILE: examples/angular/fixed/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularFixed</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/fixed/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/fixed/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
================================================
FILE: examples/angular/fixed/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/fixed/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/infinite-scroll/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/infinite-scroll/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/infinite-scroll/README.md
================================================
# @tanstack/virtualExampleAngularInfiniteScroll
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/infinite-scroll/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-infinite-scroll": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-infinite-scroll",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-infinite-scroll:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-infinite-scroll:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-infinite-scroll:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/infinite-scroll/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-infinite-scroll",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-query-experimental": "5.80.7",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/infinite-scroll/src/app/app.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
computed,
effect,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
import {
QueryClient,
injectInfiniteQuery,
provideQueryClient,
} from '@tanstack/angular-query-experimental'
async function fetchServerPage(
limit: number,
offset: number = 0,
): Promise<{ rows: string[]; nextOffset: number }> {
const rows = new Array(limit)
.fill(0)
.map((e, i) => `Async loaded row #${i + offset * limit}`)
await new Promise((r) => setTimeout(r, 500))
return { rows, nextOffset: offset + 1 }
}
@Component({
selector: 'infinite-scroll',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<p>
This infinite scroll example uses Angular Query's injectInfiniteScroll
function to fetch infinite data from a posts endpoint and then a
rowVirtualizer is used along with a loader-row placed at the bottom of the
list to trigger the next page to load.
</p>
@if (query.isLoading()) {
<p>Loading...</p>
} @else if (query.isError()) {
<span>Error: {{ query.error()!.message }}</span>
} @else {
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="row.size"
[style.transform]="'translateY(' + row.start + 'px)'"
>
{{
row.index > allRows().length - 1
? query.hasNextPage()
? 'Loading more...'
: 'Nothing more to load'
: allRows()[row.index]
}}
</div>
}
</div>
</div>
}
@if (query.isFetching() && !query.isFetchingNextPage()) {
<div>Background Updating...</div>
}
`,
styles: `
.scroll-container {
height: 500px;
width: 100%;
overflow: auto;
}
`,
providers: [provideQueryClient(new QueryClient())],
})
export class InfiniteScrollComponent {
query = injectInfiniteQuery(() => ({
queryKey: ['rows'],
queryFn: ({ pageParam }) => fetchServerPage(10, pageParam),
initialPageParam: 0,
getNextPageParam: (_lastGroup, groups) => groups.length,
}))
allRows = computed(
() => this.query.data()?.pages.flatMap((d) => d.rows) ?? [],
)
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.query.hasNextPage()
? this.allRows().length + 1
: this.allRows().length,
estimateSize: () => 100,
overscan: 5,
}))
#fetchNextPage = effect(
() => {
const lastItem =
this.virtualizer.getVirtualItems()[
this.virtualizer.getVirtualItems().length - 1
]
if (!lastItem) {
return
}
if (
lastItem.index >= this.allRows().length - 1 &&
this.query.hasNextPage() &&
!this.query.isFetchingNextPage()
) {
this.query.fetchNextPage()
}
},
{ allowSignalWrites: true },
)
}
@Component({
selector: 'app-root',
standalone: true,
imports: [InfiniteScrollComponent],
template: '<infinite-scroll />',
})
export class AppComponent {}
================================================
FILE: examples/angular/infinite-scroll/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularInfiniteScroll</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/infinite-scroll/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/infinite-scroll/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/infinite-scroll/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/infinite-scroll/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/padding/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/padding/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/padding/README.md
================================================
# @tanstack/virtualExampleAngularPadding
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/padding/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-padding": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-padding",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-padding:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-padding:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-padding:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/padding/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-padding",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/padding/src/app/app.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { ColumnVirtualizerPadding } from './column-virtualizer-padding.component'
import { GridVirtualizerPadding } from './grid-virtualizer-padding.component'
import { RowVirtualizerPadding } from './row-virtualizer-padding.component'
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
ColumnVirtualizerPadding,
GridVirtualizerPadding,
RowVirtualizerPadding,
],
template: `
<p>
These components are using <strong>dynamic</strong> sizes. This means that
each element's exact dimensions are unknown when rendered. An estimated
dimension is used to get an a initial measurement, then this measurement
is readjusted on the fly as each element is rendered. Each component has
padding at the beginning and end of its scroll container.
</p>
<row-virtualizer-padding [rows]="rows" />
<column-virtualizer-padding [columns]="columns" />
<grid-virtualizer-padding [columns]="columns" [rows]="rows" />
`,
styles: [],
})
export class AppComponent {
rows = new Array(10000)
.fill(true)
.map(() => 25 + Math.round(Math.random() * 100))
columns = new Array(10000)
.fill(true)
.map(() => 75 + Math.round(Math.random() * 100))
}
================================================
FILE: examples/angular/padding/src/app/column-virtualizer-padding.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
effect,
input,
viewChild,
viewChildren,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'column-virtualizer-padding',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Columns</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="virtualizer.getTotalSize()"
>
@for (col of virtualizer.getVirtualItems(); track col.index) {
<div
#virtualItem
[attr.data-index]="col.index"
[class.list-item-even]="col.index % 2 === 0"
[class.list-item-odd]="col.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; height: 100%;"
[style.width.px]="columns()[col.index]"
[style.transform]="'translateX(' + col.start + 'px)'"
>
Column {{ col.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 400px;
width: 400px;
overflow: auto;
}
`,
})
export class ColumnVirtualizerPadding {
columns = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.virtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
virtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: this.columns().length,
estimateSize: () => 100,
overscan: 5,
paddingStart: 100,
paddingEnd: 100,
}))
}
================================================
FILE: examples/angular/padding/src/app/grid-virtualizer-padding.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
effect,
input,
signal,
viewChild,
viewChildren,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'grid-virtualizer-padding',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Grid</h3>
<button type="button" (click)="toggleShow()">Toggle</button>
<button
type="button"
(click)="rowVirtualizer.scrollToIndex(rows().length / 2)"
>
Scroll to the middle
</button>
<button
type="button"
(click)="rowVirtualizer.scrollToIndex(rows().length - 1)"
>
Scroll to the end
</button>
@if (show()) {
<div #scrollElement class="list scroll-container">
<div
style="position: relative;"
[style.height.px]="rowVirtualizer.getTotalSize()"
[style.width.px]="columnVirtualizer.getTotalSize()"
>
@for (row of rowVirtualizer.getVirtualItems(); track row.index) {
@for (col of columnVirtualizer.getVirtualItems(); track col.index) {
<div
#virtualItem
[attr.data-colindex]="col.index"
[attr.data-rowindex]="row.index"
[class]="
col.index % 2
? row.index % 2 === 0
? 'list-item-odd'
: 'list-item-even'
: row.index % 2
? 'list-item-odd'
: 'list-item-even'
"
style="position: absolute; top: 0; left: 0;"
[style.width.px]="columns()[col.index]"
[style.height.px]="rows()[row.index]"
[style.transform]="
'translateX(' +
col.start +
'px) translateY(' +
row.start +
'px)'
"
>
<div>Cell {{ row.index }}, {{ col.index }}</div>
</div>
}
}
</div>
</div>
}
`,
styles: `
.scroll-container {
height: 400px;
width: 500px;
overflow: auto;
}
`,
})
export class GridVirtualizerPadding {
rows = input.required<number[]>()
columns = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
rowVirtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.rows().length,
estimateSize: (index) => this.rows()[index]!,
overscan: 5,
paddingStart: 200,
paddingEnd: 200,
indexAttribute: 'data-rowindex',
}))
columnVirtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: this.columns().length,
estimateSize: (index) => this.columns()[index]!,
overscan: 5,
paddingStart: 200,
paddingEnd: 200,
indexAttribute: 'data-colindex',
}))
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.rowVirtualizer.measureElement(el.nativeElement)
this.columnVirtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
show = signal(true)
toggleShow() {
this.show.update((show) => !show)
}
}
================================================
FILE: examples/angular/padding/src/app/row-virtualizer-padding.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
effect,
input,
viewChild,
viewChildren,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'row-virtualizer-padding',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Rows</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
#virtualItem
[attr.data-index]="row.index"
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="rows()[row.index]"
[style.transform]="'translateY(' + row.start + 'px)'"
>
Row {{ row.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 200px;
width: 400px;
overflow-y: auto;
}
`,
})
export class RowVirtualizerPadding {
rows = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualItems = viewChildren<ElementRef<HTMLDivElement>>('virtualItem')
#measureItems = effect(
() =>
this.virtualItems().forEach((el) => {
this.virtualizer.measureElement(el.nativeElement)
}),
{ allowSignalWrites: true },
)
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.rows().length,
estimateSize: () => 50,
paddingStart: 100,
paddingEnd: 100,
}))
}
================================================
FILE: examples/angular/padding/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularPadding</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/padding/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/padding/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/padding/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/padding/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/smooth-scroll/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/smooth-scroll/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/smooth-scroll/README.md
================================================
# @tanstack/virtualExampleAngularSmoothScroll
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/smooth-scroll/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-smooth-scroll": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-smooth-scroll",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-smooth-scroll:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-smooth-scroll:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-smooth-scroll:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/smooth-scroll/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-smooth-scroll",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/smooth-scroll/src/app/app.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
signal,
viewChild,
} from '@angular/core'
import { elementScroll, injectVirtualizer } from '@tanstack/angular-virtual'
function easeInOutQuint(t: number) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t
}
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<p>
This smooth scroll example uses the <code>scrollToFn</code> to implement a
custom scrolling function for the methods like
<code>scrollToIndex</code> and <code>scrollToOffset</code>
</p>
<div>
<button (click)="scrollToRandomIndex()">
Scroll To Random Index ({{ randomIndex() }})
</button>
</div>
<br />
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="row.size"
[style.transform]="'translateY(' + row.start + 'px)'"
>
Row {{ row.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 200px;
width: 400px;
overflow: auto;
}
`,
})
export class AppComponent {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
scrollingTime = signal(0)
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: () => 35,
overscan: 5,
scrollToFn: (offset, options, instance) => {
const duration = 1000
const start = this.scrollElement()!.nativeElement.scrollTop
const startTime = Date.now()
this.scrollingTime.set(startTime)
const run = () => {
if (this.scrollingTime() !== startTime) return
const now = Date.now()
const elapsed = now - startTime
const progress = easeInOutQuint(Math.min(elapsed / duration, 1))
const interpolated = start + (offset - start) * progress
if (elapsed < duration) {
elementScroll(interpolated, options, instance)
requestAnimationFrame(run)
} else {
elementScroll(interpolated, options, instance)
}
}
requestAnimationFrame(run)
},
}))
randomIndex = signal(Math.floor(Math.random() * 10000))
scrollToRandomIndex() {
this.virtualizer.scrollToIndex(this.randomIndex())
this.randomIndex.set(Math.floor(Math.random() * 10000))
}
}
================================================
FILE: examples/angular/smooth-scroll/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularSmoothScroll</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/smooth-scroll/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/smooth-scroll/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/smooth-scroll/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/smooth-scroll/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/sticky/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/sticky/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/sticky/README.md
================================================
# @tanstack/virtualExampleAngularSticky
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/sticky/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-sticky": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-sticky",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-sticky:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-sticky:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-sticky:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/sticky/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-sticky",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@faker-js/faker": "^8.4.1",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/sticky/src/app/app.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
computed,
viewChild,
} from '@angular/core'
import { faker } from '@faker-js/faker'
import {
injectVirtualizer,
defaultRangeExtractor,
} from '@tanstack/angular-virtual'
const groupedNames: Record<string, string[]> = {}
Array.from({ length: 1000 })
.map(() => faker.person.firstName())
.sort()
.forEach((name) => {
const char = name[0]
if (!groupedNames[char]) {
groupedNames[char] = []
}
groupedNames[char].push(name)
})
const groups = Object.keys(groupedNames)
const rows = groups.reduce(
(acc: string[], k) => [...acc, k, ...groupedNames[k]],
[],
)
const stickyIndexes = groups.map((gn) => rows.findIndex((n) => n === gn))
const stickyIndexesSet = new Set(stickyIndexes)
const reversedStickyIndexes = [...stickyIndexes].reverse()
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
[attr.data-index]="row.index"
style="top: 0; left: 0; width: 100%; background: #fff"
[style.zIndex]="isSticky(row.index) ? 1 : null"
[style.borderBottom]="
isSticky(row.index) ? '1px solid #ddd' : 'none'
"
[style.position]="isActiveSticky(row.index) ? 'sticky' : 'absolute'"
[style.height.px]="row.size"
[style.transform]="
isActiveSticky(row.index)
? null
: 'translateY(' + row.start + 'px)'
"
>
{{ rows[row.index] }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 300px;
width: 400px;
overflow: auto;
}
`,
})
export class AppComponent {
rows = rows
isSticky = (index: number) => stickyIndexesSet.has(index)
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.rows.length,
estimateSize: () => 50,
rangeExtractor: (range) => {
const next = new Set([
reversedStickyIndexes.find((index) => range.startIndex >= index)!,
...defaultRangeExtractor(range),
])
return [...next].sort((a, b) => a - b)
},
}))
activeStickyIndex = computed(() => {
return this.virtualizer.getVirtualItems()[0]?.index
})
isActiveSticky = (index: number) => this.activeStickyIndex() === index
}
================================================
FILE: examples/angular/sticky/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularSticky</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/sticky/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/sticky/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/sticky/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/sticky/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/table/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/table/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/table/README.md
================================================
# @tanstack/virtualExampleAngularTable
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/table/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-table": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-table",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-table:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-table:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-table:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/table/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-table",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@faker-js/faker": "^8.4.1",
"@tanstack/angular-table": "8.21.3",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/table/src/app/app.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
computed,
signal,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
import {
ColumnDef,
createAngularTable,
getCoreRowModel,
getSortedRowModel,
SortingState,
FlexRenderDirective,
SortDirection,
} from '@tanstack/angular-table'
import { makeData, type Person } from './make-data'
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FlexRenderDirective],
template: `
<p>
For tables, the basis for the offset of the translate css function is from
the row's initial position itself. Because of this, we need to calculate
the translateY pixel count different and base it off the the index.
</p>
<br />
<div #scrollElement class="list scroll-container">
<div [style.height.px]="virtualizer.getTotalSize()">
<table>
<thead>
@for (
headerGroup of table.getHeaderGroups();
track headerGroup.id
) {
<tr>
@for (header of headerGroup.headers; track header.id) {
<th
[attr.colspan]="header.colSpan"
[style.width.px]="header.getSize()"
>
@if (!header.isPlaceholder) {
<div
[class.cursor-pointer]="header.column.getCanSort()"
[class.select-none]="header.column.getCanSort()"
(click)="
header.column.getToggleSortingHandler()?.($event)
"
>
<ng-container
*flexRender="
header.column.columnDef.header;
props: header.getContext();
let headerText
"
>
<span>{{ headerText }}</span>
{{ getSortIcon(header.column.getIsSorted()) }}
</ng-container>
</div>
}
</th>
}
</tr>
}
</thead>
<tbody>
@for (
virtualRow of virtualizer.getVirtualItems();
track data[virtualRow.index].id
) {
<tr
[style.height.px]="virtualRow.size"
[style.transform]="
'translateY(' +
(virtualRow.start - $index * virtualRow.size) +
'px)'
"
>
@for (
cell of rows()[virtualRow.index].getVisibleCells();
track cell.id
) {
<td>
<ng-container
*flexRender="
cell.column.columnDef.cell;
props: cell.getContext();
let cellText
"
>
<span>{{ cellText }}</span>
</ng-container>
</td>
}
</tr>
}
</tbody>
</table>
</div>
</div>
`,
styles: `
.scroll-container {
height: 600px;
overflow: auto;
}
`,
})
export class AppComponent {
data = makeData(50_000)
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
sorting = signal<SortingState>([])
sortIcons = { asc: '🔼', desc: '🔽' }
getSortIcon(sorting: false | SortDirection) {
return sorting ? this.sortIcons[sorting] : null
}
columns: ColumnDef<Person>[] = [
{
accessorKey: 'id',
header: 'ID',
size: 60,
},
{
accessorKey: 'firstName',
cell: (info) => info.getValue(),
},
{
accessorFn: (row) => row.lastName,
id: 'lastName',
cell: (info) => info.getValue(),
header: 'Last Name',
},
{
accessorKey: 'age',
header: () => 'Age',
size: 50,
},
{
accessorKey: 'visits',
header: 'Visits',
size: 50,
},
{
accessorKey: 'status',
header: 'Status',
},
{
accessorKey: 'progress',
header: 'Profile Progress',
size: 80,
},
{
accessorKey: 'createdAt',
header: 'Created At',
cell: (info) => info.getValue<Date>().toLocaleString(),
},
]
table = createAngularTable(() => ({
data: this.data,
columns: this.columns,
state: {
sorting: this.sorting(),
},
onSortingChange: (updaterOrValue) =>
typeof updaterOrValue === 'function'
? this.sorting.update(updaterOrValue)
: this.sorting.set(updaterOrValue),
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
debugTable: true,
}))
rows = computed(() => this.table.getRowModel().rows)
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.data.length,
estimateSize: () => 34,
overscan: 20,
}))
}
================================================
FILE: examples/angular/table/src/app/make-data.ts
================================================
import { faker } from '@faker-js/faker'
export type Person = {
id: number
firstName: string
lastName: string
age: number
visits: number
progress: number
status: 'relationship' | 'complicated' | 'single'
createdAt: Date
}
const range = (len: number) => {
const arr: number[] = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}
const newPerson = (index: number): Person => {
return {
id: index + 1,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
age: faker.number.int(40),
visits: faker.number.int(1000),
progress: faker.number.int(100),
createdAt: faker.datatype.datetime({ max: new Date().getTime() }),
status: faker.helpers.shuffle<Person['status']>([
'relationship',
'complicated',
'single',
])[0]!,
}
}
export function makeData(...lens: number[]) {
const makeDataLevel = (depth = 0): Person[] => {
const len = lens[depth]!
return range(len).map((d): Person => {
return {
...newPerson(d),
}
})
}
return makeDataLevel()
}
================================================
FILE: examples/angular/table/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularTable</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/table/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/table/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/table/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/table/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/variable/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/variable/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/variable/README.md
================================================
# @tanstack/virtualExampleAngularVariable
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/variable/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-variable": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-variable",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-variable:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-variable:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-variable:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/variable/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-variable",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/variable/src/app/app.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { ColumnVirtualizerVariable } from './column-virtualizer-variable.component'
import { GridVirtualizerVariable } from './grid-virtualizer-variable.component'
import { RowVirtualizerVariable } from './row-virtualizer-variable.component'
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
ColumnVirtualizerVariable,
GridVirtualizerVariable,
RowVirtualizerVariable,
],
template: `
<p>
These components are using <strong>variable</strong> sizes. This means
that each element has a unique, but knowable dimension at render time.
</p>
<row-virtualizer-variable [rows]="rows" />
<column-virtualizer-variable [columns]="columns" />
<grid-virtualizer-variable [columns]="columns" [rows]="rows" />
`,
styles: [],
})
export class AppComponent {
rows = new Array(10000)
.fill(true)
.map(() => 25 + Math.round(Math.random() * 100))
columns = new Array(10000)
.fill(true)
.map(() => 75 + Math.round(Math.random() * 100))
}
================================================
FILE: examples/angular/variable/src/app/column-virtualizer-variable.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
input,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'column-virtualizer-variable',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Columns</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="virtualizer.getTotalSize()"
>
@for (col of virtualizer.getVirtualItems(); track col.index) {
<div
[attr.data-index]="col.index"
[class.list-item-even]="col.index % 2 === 0"
[class.list-item-odd]="col.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; height: 100%;"
[style.width.px]="col.size"
[style.transform]="'translateX(' + col.start + 'px)'"
>
Col {{ col.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 100px;
width: 400px;
overflow: auto;
}
`,
})
export class ColumnVirtualizerVariable {
columns = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: (index) => this.columns()[index]!,
overscan: 5,
}))
}
================================================
FILE: examples/angular/variable/src/app/grid-virtualizer-variable.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
input,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'grid-virtualizer-variable',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Grid</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; height: 100%;"
[style.width.px]="columnVirtualizer.getTotalSize()"
[style.height.px]="rowVirtualizer.getTotalSize()"
>
@for (
row of rowVirtualizer.getVirtualItems();
track row.index;
let rowEven = $even
) {
@for (
col of columnVirtualizer.getVirtualItems();
track col.index;
let colEven = $even
) {
<div
[attr.data-index]="col.index"
[class]="
col.index % 2
? row.index % 2 === 0
? 'list-item-odd'
: 'list-item-even'
: row.index % 2
? 'list-item-odd'
: 'list-item-even'
"
style="position: absolute; top: 0; left: 0;"
[style.height.px]="row.size"
[style.width.px]="col.size"
[style.transform]="
'translateX(' +
col.start +
'px)' +
'translateY(' +
row.start +
'px)'
"
>
Cell {{ row.index }}, {{ col.index }}
</div>
}
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 500px;
width: 500px;
overflow: auto;
}
`,
})
export class GridVirtualizerVariable {
rows = input.required<number[]>()
columns = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
rowVirtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: (index) => this.rows()[index]!,
overscan: 5,
}))
columnVirtualizer = injectVirtualizer(() => ({
horizontal: true,
scrollElement: this.scrollElement(),
count: 10000,
estimateSize: (index) => this.columns()[index]!,
overscan: 5,
}))
}
================================================
FILE: examples/angular/variable/src/app/row-virtualizer-variable.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
input,
viewChild,
} from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
@Component({
standalone: true,
selector: 'row-virtualizer-variable',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h3 style="margin-top: 2rem">Rows</h3>
<div #scrollElement class="list scroll-container">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.index) {
<div
[attr.data-index]="row.index"
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="row.size"
[style.transform]="'translateY(' + row.start + 'px)'"
>
Row {{ row.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 200px;
width: 400px;
overflow: auto;
}
`,
})
export class RowVirtualizerVariable {
rows = input.required<number[]>()
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectVirtualizer(() => ({
scrollElement: this.scrollElement(),
count: this.rows().length,
estimateSize: (index) => this.rows()[index]!,
overscan: 5,
}))
}
================================================
FILE: examples/angular/variable/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularVariable</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/variable/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/variable/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/variable/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/variable/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/angular/window/.devcontainer/devcontainer.json
================================================
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
================================================
FILE: examples/angular/window/.gitignore
================================================
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
================================================
FILE: examples/angular/window/README.md
================================================
# @tanstack/virtualExampleAngularWindow
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
================================================
FILE: examples/angular/window/angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"projects": {
"@tanstack/virtual-example-angular-window": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tanstack/virtual-example-angular-window",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "@tanstack/virtual-example-angular-window:build:production"
},
"development": {
"buildTarget": "@tanstack/virtual-example-angular-window:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "@tanstack/virtual-example-angular-window:build"
}
}
}
}
}
}
================================================
FILE: examples/angular/window/package.json
================================================
{
"name": "@tanstack/virtual-example-angular-window",
"private": true,
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/forms": "^18.1.0",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@tanstack/angular-virtual": "^4.0.11",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.0",
"@angular/cli": "^18.1.0",
"@angular/compiler-cli": "^18.1.0",
"typescript": "5.4.5"
}
}
================================================
FILE: examples/angular/window/src/app/app.component.ts
================================================
import {
ChangeDetectionStrategy,
Component,
ElementRef,
viewChild,
} from '@angular/core'
import { injectWindowVirtualizer } from '@tanstack/angular-virtual'
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<p>
In many cases, when implementing a virtualizer with a window as the
scrolling element, developers often find the need to specify a
"scrollMargin." The scroll margin is a crucial setting that defines the
space or gap between the start of the page and the edges of the list.
</p>
<h3>Window Scroller</h3>
<div #scrollElement class="list">
<div
style="position: relative; width: 100%;"
[style.height.px]="virtualizer.getTotalSize()"
>
@for (row of virtualizer.getVirtualItems(); track row.key) {
<div
#virtualItem
[class.list-item-even]="row.index % 2 === 0"
[class.list-item-odd]="row.index % 2 !== 0"
style="position: absolute; top: 0; left: 0; width: 100%;"
[style.height.px]="row.size"
[style.transform]="
'translateY(' +
(row.start - virtualizer.options().scrollMargin) +
'px)'
"
>
Row {{ row.index }}
</div>
}
</div>
</div>
`,
styles: `
.scroll-container {
height: 400px;
width: 400px;
overflow-y: auto;
contain: 'strict';
}
`,
})
export class AppComponent {
scrollElement = viewChild<ElementRef<HTMLDivElement>>('scrollElement')
virtualizer = injectWindowVirtualizer(() => ({
count: 10000,
estimateSize: () => 35,
overscan: 5,
scrollMargin: this.scrollElement()?.nativeElement.offsetTop,
}))
}
================================================
FILE: examples/angular/window/src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@tanstack/virtualExampleAngularWindow</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
================================================
FILE: examples/angular/window/src/main.ts
================================================
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'
bootstrapApplication(AppComponent).catch((err) => console.error(err))
================================================
FILE: examples/angular/window/src/styles.css
================================================
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.list-item-odd {
background-color: #fff;
}
button {
border: 1px solid gray;
}
================================================
FILE: examples/angular/window/tsconfig.app.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
================================================
FILE: examples/angular/window/tsconfig.json
================================================
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
================================================
FILE: examples/lit/dynamic/.gitignore
================================================
node_modules
.DS_Store
dist
dist-ssr
*.local
================================================
FILE: examples/lit/dynamic/README.md
================================================
# Example
To run this example:
- `npm install` or `npm`
- `npm run start` or `npm run start`
================================================
FILE: examples/lit/dynamic/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.ts"></script>
<my-app></my-app>
</body>
</html>
================================================
FILE: examples/lit/dynamic/package.json
================================================
{
"name": "tanstack-lit-virtual-example-dynamic",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
"@tanstack/lit-virtual": "^3.13.24",
"@tanstack/virtual-core": "^3.13.23",
"lit": "^3.3.0"
},
"devDependencies": {
"@types/node": "^24.5.2",
"typescript": "5.4.5",
"vite": "^5.4.19"
}
}
================================================
FILE: examples/lit/dynamic/src/index.css
================================================
html {
font-family: sans-serif;
font-size: 14px;
}
body {
padding: 1rem;
}
================================================
FILE: examples/lit/dynamic/src/main.ts
================================================
import { customElement, property } from 'lit/decorators.js'
import { Ref, createRef, ref } from 'lit/directives/ref.js'
import { html, LitElement } from 'lit'
import { faker } from '@faker-js/faker'
import { repeat } from 'lit/directives/repeat.js'
import {
VirtualizerController,
WindowVirtualizerController,
} from '@tanstack/lit-virtual'
interface Column {
key: string
name: string
width: number
}
function randomNumber(min: number, max: number) {
return faker.number.int({ min, max })
}
const sentences = new Array(10000)
.fill(true)
.map(() => faker.lorem.sentence(randomNumber(20, 70)))
const generateColumns = (count: number) => {
return new Array(count).fill(0).map((_, i) => {
const key: string = i.toString()
return {
key,
name: `Column ${i}`,
width: randomNumber(75, 300),
}
})
}
const generateData = (columns: Column[], count = 300) => {
return new Array(count).fill(0).map((_, rowIndex) =>
columns.reduce<string[]>((acc, _curr, colIndex) => {
// simulate dynamic size cells
const val = faker.lorem.lines(((rowIndex + colIndex) % 10) + 1)
acc.push(val)
return acc
}, []),
)
}
@customElement('row-virtualizer-dynamic')
class RowVirtualizerDynamic extends LitElement {
private scrollElementRef: Ref<HTMLDivElement> = createRef()
private virtualizerController: VirtualizerController<HTMLDivElement, Element>
constructor() {
super()
this.virtualizerController = new VirtualizerController(this, {
getScrollElement: () => this.scrollElementRef.value,
count: sentences.length,
estimateSize: () => 45,
})
}
render() {
const virtualizer = this.virtualizerController.getVirtualizer()
const virtualRows = virtualizer.getVirtualItems()
const count = sentences.length
return html`
<div>
<button @click=${() => virtualizer.scrollToIndex(0)}>
scroll to the top
</button>
<button @click=${() => virtualizer.scrollToIndex(count / 2)}>
scroll to the middle
</button>
<button @click=${() => virtualizer.scrollToIndex(count - 1)}>
scroll to the end
</button>
<div class="list scroll-container" ${ref(this.scrollElementRef)}>
<div
style="position: relative; height: ${virtualizer.getTotalSize()}px; width: 100%;"
>
<div
style="position:absolute;top:0;left:0;width:100%;transform:translateY(${virtualRows[0]
? virtualRows[0].start
: 0}px);"
>
${repeat(
virtualRows,
(virtualRow) => virtualRow.key,
(virtualRow) =>
html` <div
data-index="${virtualRow.index}"
${ref(virtualizer.measureElement)}
class="${virtualRow.index % 2 === 0
? 'list-item-even'
: 'list-item-odd'}"
>
<div style="padding: 10px 0;">
<div>Row ${virtualRow.index}</div>
<div>${sentences[virtualRow.index]}</div>
</div>
</div>`,
)}
</div>
</div>
</div>
</div>
<style>
.list {
border: 1px solid #e6e4dc;
max-width: 100%;
}
.list-item-even,
.list-item-odd {
display: flex;
align-items: center;
justify-content: center;
}
.list-item-even {
background-color: #e6e4dc;
}
.scroll-container {
height: 400px;
width: 400px;
overflow-y: auto;
}
</style>
`
}
}
@customElement('column-virtualizer-dynamic')
class ColumnVirtualizerDynamic extends LitElement {
private scrollElementRef: Ref<HTMLDivElement> = createRef()
private virtualizerController: VirtualizerController<HTMLDivElement, Element>
constructor() {
super()
this.virtualizerController = new VirtualizerController(this, {
getScrollElement: () => this.scrollElementRef.value,
count: sentences.length,
estimateSize: () => 45,
horizontal: true,
})
}
render() {
const virtualizer = this.virtualizerController.getVirtualizer()
const virtualColumns = virtualizer.getVirtualItems()
return html`
<div>
<div class="list scroll-container" ${ref(this.scrollElementRef)}>
<div
style="position: relative; width: ${virtualizer.getTotalSize()}px; height: 100%;"
>
${repeat(
virtualColumns,
(virtualColumn) => virtualColumn.key,
(virtualColumn) => html`
<div
data-index="${virtualColumn.index}"
style="position:absolute;top:0;left:0;height:100%;transform:translateX(${virtualColumn.start}px)"
${ref(virtualizer.measureElement)}
class="${virtualColumn.index % 2 === 0
? 'list-item-even'
: 'list-item-odd'}"
>
<div style="width:${sentences[virtualColumn.index].length}px">
<div>Column ${virtualColumn.index}</div>
<div>${sentences[virtualColumn.index]}</div>
</div>
</div>
`,
)}
</div>
</div>
</div>
gitextract_lr2rhb18/ ├── .changeset/ │ └── config.json ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ └── config.yml │ ├── pull_request_template.md │ ├── renovate.json │ └── workflows/ │ ├── autofix.yml │ ├── pr.yml │ └── release.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs/ │ ├── api/ │ │ ├── virtual-item.md │ │ └── virtualizer.md │ ├── config.json │ ├── framework/ │ │ ├── angular/ │ │ │ └── angular-virtual.md │ │ ├── lit/ │ │ │ └── lit-virtual.md │ │ ├── react/ │ │ │ └── react-virtual.md │ │ ├── solid/ │ │ │ └── solid-virtual.md │ │ ├── svelte/ │ │ │ └── svelte-virtual.md │ │ └── vue/ │ │ └── vue-virtual.md │ ├── installation.md │ └── introduction.md ├── eslint.config.js ├── examples/ │ ├── angular/ │ │ ├── dynamic/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── app.config.ts │ │ │ │ │ ├── app.routes.ts │ │ │ │ │ ├── column-virtualizer-dynamic.component.ts │ │ │ │ │ ├── grid-virtualizer-dynamic.component.ts │ │ │ │ │ ├── row-virtualizer-dynamic-window.component.ts │ │ │ │ │ ├── row-virtualizer-dynamic.component.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── fixed/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── column-virtualizer-fixed.component.ts │ │ │ │ │ ├── grid-virtualizer-fixed.component.ts │ │ │ │ │ └── row-virtualizer-fixed.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── infinite-scroll/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ └── app.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── padding/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── column-virtualizer-padding.component.ts │ │ │ │ │ ├── grid-virtualizer-padding.component.ts │ │ │ │ │ └── row-virtualizer-padding.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── smooth-scroll/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ └── app.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── sticky/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ └── app.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── table/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.component.ts │ │ │ │ │ └── make-data.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ ├── variable/ │ │ │ ├── .devcontainer/ │ │ │ │ └── devcontainer.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── angular.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── column-virtualizer-variable.component.ts │ │ │ │ │ ├── grid-virtualizer-variable.component.ts │ │ │ │ │ └── row-virtualizer-variable.component.ts │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.json │ │ └── window/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── angular.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ └── app.component.ts │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ └── styles.css │ │ ├── tsconfig.app.json │ │ └── tsconfig.json │ ├── lit/ │ │ ├── dynamic/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.ts │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ └── fixed/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.css │ │ │ └── main.ts │ │ ├── tsconfig.json │ │ └── vite.config.js │ ├── react/ │ │ ├── dynamic/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── fixed/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── infinite-scroll/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── padding/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── scroll-padding/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── smooth-scroll/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── sticky/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── table/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ ├── main.tsx │ │ │ │ └── makeData.ts │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── variable/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ └── window/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.css │ │ │ └── main.tsx │ │ ├── tsconfig.json │ │ └── vite.config.js │ ├── svelte/ │ │ ├── dynamic/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.svelte │ │ │ │ ├── ColumnVirtualizerDynamic.svelte │ │ │ │ ├── GridVirtualizerDynamic.svelte │ │ │ │ ├── RowVirtualizerDynamic.svelte │ │ │ │ ├── RowVirtualizerDynamicWindow.svelte │ │ │ │ ├── app.css │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── svelte.config.js │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── fixed/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.svelte │ │ │ │ ├── ColumnVirtualizerFixed.svelte │ │ │ │ ├── GridVirtualizerFixed.svelte │ │ │ │ ├── RowVirtualizerFixed.svelte │ │ │ │ ├── app.css │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── svelte.config.js │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── infinite-scroll/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.svelte │ │ │ │ ├── InfiniteRows.svelte │ │ │ │ ├── app.css │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── svelte.config.js │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── smooth-scroll/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.svelte │ │ │ │ ├── app.css │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── svelte.config.js │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── sticky/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.svelte │ │ │ │ ├── app.css │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── svelte.config.js │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ └── table/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.svelte │ │ │ ├── app.css │ │ │ ├── main.ts │ │ │ ├── makeData.ts │ │ │ └── vite-env.d.ts │ │ ├── svelte.config.js │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── vue/ │ ├── dynamic/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── components/ │ │ │ │ ├── ColumnVirtualizerDynamic.vue │ │ │ │ ├── GridVirtualizerDynamic.vue │ │ │ │ ├── RowVirtualizerDynamic.vue │ │ │ │ ├── RowVirtualizerDynamicWindow.vue │ │ │ │ └── utils.ts │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── fixed/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── components/ │ │ │ │ ├── ColumnVirtualizerFixed.vue │ │ │ │ ├── GridVirtualizerFixed.vue │ │ │ │ └── RowVirtualizerFixed.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── infinite-scroll/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── padding/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── components/ │ │ │ │ ├── ColumnVirtualizerPadding.vue │ │ │ │ ├── GridVirtualizerPadding.vue │ │ │ │ └── RowVirtualizerPadding.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── scroll-padding/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── smooth-scroll/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── sticky/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── main.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── table/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── main.ts │ │ │ ├── makeData.ts │ │ │ ├── style.css │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── variable/ │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src/ │ │ ├── App.vue │ │ ├── components/ │ │ │ ├── ColumnVirtualizerVariable.vue │ │ │ ├── GridVirtualizerVariable.vue │ │ │ ├── MasonryHorizontalVirtualizerVariable.vue │ │ │ ├── MasonryVerticalVirtualizerVariable.vue │ │ │ └── RowVirtualizerVariable.vue │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── knip.json ├── media/ │ └── logo.sketch ├── nx.json ├── package.json ├── packages/ │ ├── angular-virtual/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── ng-package.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── proxy.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── lit-virtual/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── tests/ │ │ │ └── index.test.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── react-virtual/ │ │ ├── CHANGELOG.md │ │ ├── e2e/ │ │ │ └── app/ │ │ │ ├── measure-element/ │ │ │ │ ├── index.html │ │ │ │ └── main.tsx │ │ │ ├── scroll/ │ │ │ │ ├── index.html │ │ │ │ └── main.tsx │ │ │ ├── smooth-scroll/ │ │ │ │ ├── index.html │ │ │ │ └── main.tsx │ │ │ ├── stale-index/ │ │ │ │ ├── index.html │ │ │ │ └── main.tsx │ │ │ ├── test/ │ │ │ │ ├── measure-element.spec.ts │ │ │ │ ├── scroll.spec.ts │ │ │ │ ├── smooth-scroll.spec.ts │ │ │ │ └── stale-index.spec.ts │ │ │ ├── tsconfig.json │ │ │ └── vite.config.ts │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── playwright.config.ts │ │ ├── src/ │ │ │ └── index.tsx │ │ ├── tests/ │ │ │ ├── index.test.tsx │ │ │ └── test-setup.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── solid-virtual/ │ │ ├── CHANGELOG.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── svelte-virtual/ │ │ ├── CHANGELOG.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── svelte.config.js │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── virtual-core/ │ │ ├── CHANGELOG.md │ │ ├── eslint.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ ├── tests/ │ │ │ └── index.test.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── vue-virtual/ │ ├── CHANGELOG.md │ ├── eslint.config.js │ ├── package.json │ ├── src/ │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-workspace.yaml ├── prettier.config.js ├── scripts/ │ └── verify-links.ts └── tsconfig.json
SYMBOL INDEX (169 symbols across 58 files)
FILE: examples/angular/dynamic/src/app/app.component.ts
class AppComponent (line 27) | class AppComponent {}
FILE: examples/angular/dynamic/src/app/column-virtualizer-dynamic.component.ts
class ColumnVirtualizerDynamic (line 50) | class ColumnVirtualizerDynamic {
FILE: examples/angular/dynamic/src/app/grid-virtualizer-dynamic.component.ts
class GridVirtualizerDynamic (line 72) | class GridVirtualizerDynamic {
method constructor (line 79) | constructor() {
FILE: examples/angular/dynamic/src/app/row-virtualizer-dynamic-window.component.ts
class RowVirtualizerDynamicWindow (line 61) | class RowVirtualizerDynamicWindow {
method constructor (line 66) | constructor() {
FILE: examples/angular/dynamic/src/app/row-virtualizer-dynamic.component.ts
class RowVirtualizerDynamic (line 72) | class RowVirtualizerDynamic {
FILE: examples/angular/dynamic/src/app/utils.ts
type Column (line 11) | interface Column {
FILE: examples/angular/fixed/src/app/app.component.ts
class AppComponent (line 24) | class AppComponent {}
FILE: examples/angular/fixed/src/app/column-virtualizer-fixed.component.ts
class ColumnVirtualizerFixed (line 43) | class ColumnVirtualizerFixed {
FILE: examples/angular/fixed/src/app/grid-virtualizer-fixed.component.ts
class GridVirtualizerFixed (line 69) | class GridVirtualizerFixed {
FILE: examples/angular/fixed/src/app/row-virtualizer-fixed.component.ts
class RowVirtualizerFixed (line 43) | class RowVirtualizerFixed {
FILE: examples/angular/infinite-scroll/src/app/app.component.ts
function fetchServerPage (line 16) | async function fetchServerPage(
class InfiniteScrollComponent (line 83) | class InfiniteScrollComponent {
class AppComponent (line 133) | class AppComponent {}
FILE: examples/angular/padding/src/app/app.component.ts
class AppComponent (line 31) | class AppComponent {
FILE: examples/angular/padding/src/app/column-virtualizer-padding.component.ts
class ColumnVirtualizerPadding (line 47) | class ColumnVirtualizerPadding {
FILE: examples/angular/padding/src/app/grid-virtualizer-padding.component.ts
class GridVirtualizerPadding (line 81) | class GridVirtualizerPadding {
method toggleShow (line 121) | toggleShow() {
FILE: examples/angular/padding/src/app/row-virtualizer-padding.component.ts
class RowVirtualizerPadding (line 47) | class RowVirtualizerPadding {
FILE: examples/angular/smooth-scroll/src/app/app.component.ts
function easeInOutQuint (line 10) | function easeInOutQuint(t: number) {
class AppComponent (line 57) | class AppComponent {
method scrollToRandomIndex (line 93) | scrollToRandomIndex() {
FILE: examples/angular/sticky/src/app/app.component.ts
class AppComponent (line 75) | class AppComponent {
FILE: examples/angular/table/src/app/app.component.ts
class AppComponent (line 116) | class AppComponent {
method getSortIcon (line 125) | getSortIcon(sorting: false | SortDirection) {
FILE: examples/angular/table/src/app/make-data.ts
type Person (line 3) | type Person = {
function makeData (line 39) | function makeData(...lens: number[]) {
FILE: examples/angular/variable/src/app/app.component.ts
class AppComponent (line 28) | class AppComponent {
FILE: examples/angular/variable/src/app/column-virtualizer-variable.component.ts
class ColumnVirtualizerVariable (line 44) | class ColumnVirtualizerVariable {
FILE: examples/angular/variable/src/app/grid-virtualizer-variable.component.ts
class GridVirtualizerVariable (line 70) | class GridVirtualizerVariable {
FILE: examples/angular/variable/src/app/row-virtualizer-variable.component.ts
class RowVirtualizerVariable (line 44) | class RowVirtualizerVariable {
FILE: examples/angular/window/src/app/app.component.ts
class AppComponent (line 54) | class AppComponent {
FILE: examples/lit/dynamic/src/main.ts
type Column (line 11) | interface Column {
function randomNumber (line 17) | function randomNumber(min: number, max: number) {
class RowVirtualizerDynamic (line 49) | @customElement('row-virtualizer-dynamic')
method constructor (line 55) | constructor() {
method render (line 64) | render() {
class ColumnVirtualizerDynamic (line 137) | @customElement('column-virtualizer-dynamic')
method constructor (line 143) | constructor() {
method render (line 153) | render() {
class GridVirtualizerDynamic (line 210) | @customElement('grid-virtualizer-dynamic')
method getColumnWidth (line 226) | private getColumnWidth(index: number) {
method connectedCallback (line 230) | connectedCallback() {
method render (line 246) | render() {
class MyApp (line 307) | class MyApp extends LitElement {
method render (line 308) | protected render() {
FILE: examples/lit/fixed/src/main.ts
type Column (line 11) | interface Column {
function randomNumber (line 17) | function randomNumber(min: number, max: number) {
class RowVirtualizerFixed (line 49) | @customElement('row-virtualizer-fixed')
method constructor (line 55) | constructor() {
method render (line 65) | render() {
class ColumnVirtualizerFixed (line 118) | @customElement('column-virtualizer-fixed')
method constructor (line 124) | constructor() {
method render (line 134) | render() {
class GridVirtualizerFixed (line 187) | @customElement('grid-virtualizer-fixed')
method constructor (line 200) | constructor() {
method render (line 218) | render() {
class MyApp (line 282) | class MyApp extends LitElement {
method render (line 283) | protected render() {
FILE: examples/react/dynamic/src/main.tsx
function RowVirtualizerDynamic (line 16) | function RowVirtualizerDynamic() {
function ColumnVirtualizerDynamic (line 118) | function ColumnVirtualizerDynamic() {
type Column (line 170) | interface Column {
function GridVirtualizerDynamic (line 176) | function GridVirtualizerDynamic({
function RowVirtualizerExperimental (line 298) | function RowVirtualizerExperimental() {
function App (line 402) | function App() {
FILE: examples/react/fixed/src/main.tsx
function App (line 8) | function App() {
function RowVirtualizerFixed (line 42) | function RowVirtualizerFixed() {
function ColumnVirtualizerFixed (line 92) | function ColumnVirtualizerFixed() {
function GridVirtualizerFixed (line 145) | function GridVirtualizerFixed() {
FILE: examples/react/infinite-scroll/src/main.tsx
function fetchServerPage (line 15) | async function fetchServerPage(
function App (line 28) | function App() {
FILE: examples/react/padding/src/main.tsx
function App (line 16) | function App() {
function RowVirtualizerDynamic (line 42) | function RowVirtualizerDynamic({ rows }: { rows: Array<number> }) {
function ColumnVirtualizerDynamic (line 95) | function ColumnVirtualizerDynamic({ columns }: { columns: Array<number> ...
function GridVirtualizerDynamic (line 151) | function GridVirtualizerDynamic({
FILE: examples/react/scroll-padding/src/main.tsx
function App (line 9) | function App() {
FILE: examples/react/smooth-scroll/src/main.tsx
function easeInOutQuint (line 9) | function easeInOutQuint(t: number) {
function App (line 13) | function App() {
FILE: examples/react/table/src/main.tsx
function ReactTableVirtualized (line 16) | function ReactTableVirtualized() {
function App (line 161) | function App() {
FILE: examples/react/table/src/makeData.ts
type Person (line 3) | type Person = {
function makeData (line 39) | function makeData(...lens: number[]) {
FILE: examples/react/variable/src/main.tsx
function App (line 16) | function App() {
function RowVirtualizerVariable (line 57) | function RowVirtualizerVariable({ rows }: { rows: Array<number> }) {
function ColumnVirtualizerVariable (line 107) | function ColumnVirtualizerVariable({ columns }: { columns: Array<number>...
function GridVirtualizerVariable (line 160) | function GridVirtualizerVariable({
function MasonryVerticalVirtualizerVariable (line 236) | function MasonryVerticalVirtualizerVariable({ rows }: { rows: Array<numb...
function MasonryHorizontalVirtualizerVariable (line 287) | function MasonryHorizontalVirtualizerVariable({
FILE: examples/react/window/src/main.tsx
function Example (line 8) | function Example() {
function App (line 57) | function App() {
FILE: examples/svelte/table/src/makeData.ts
type Person (line 3) | type Person = {
function makeData (line 39) | function makeData(...lens: number[]) {
FILE: examples/vue/dynamic/src/components/utils.ts
type Column (line 3) | interface Column {
FILE: examples/vue/table/src/makeData.ts
type Person (line 3) | type Person = {
function makeData (line 39) | function makeData(...lens: number[]) {
FILE: packages/angular-virtual/src/index.ts
function createVirtualizerBase (line 27) | function createVirtualizerBase<
function injectVirtualizer (line 81) | function injectVirtualizer<
function isElementRef (line 111) | function isElementRef<T extends Element>(
function injectWindowVirtualizer (line 117) | function injectWindowVirtualizer<TItemElement extends Element>(
FILE: packages/angular-virtual/src/proxy.ts
function proxyVirtualizer (line 6) | function proxyVirtualizer<
function toComputed (line 92) | function toComputed<V extends Virtualizer<any, any>>(
function serializeArgs (line 115) | function serializeArgs(...args: Array<any>) {
FILE: packages/angular-virtual/src/types.ts
type AngularVirtualizer (line 4) | type AngularVirtualizer<
FILE: packages/lit-virtual/src/index.ts
class VirtualizerControllerBase (line 13) | class VirtualizerControllerBase<
method constructor (line 23) | constructor(
method getVirtualizer (line 38) | public getVirtualizer() {
method hostConnected (line 42) | hostConnected() {
method hostUpdated (line 46) | hostUpdated() {
method hostDisconnected (line 50) | hostDisconnected() {
class VirtualizerController (line 55) | class VirtualizerController<
method constructor (line 59) | constructor(
class WindowVirtualizerController (line 75) | class WindowVirtualizerController<
method constructor (line 78) | constructor(
FILE: packages/lit-virtual/tests/index.test.ts
class List (line 13) | @customElement('test-list')
method constructor (line 19) | constructor() {
method render (line 31) | render() {
FILE: packages/react-virtual/e2e/app/measure-element/main.tsx
type Item (line 5) | interface Item {
constant INITIAL_ITEMS (line 10) | const INITIAL_ITEMS: Array<Item> = [
FILE: packages/react-virtual/e2e/app/scroll/main.tsx
function getRandomInt (line 5) | function getRandomInt(min: number, max: number) {
FILE: packages/react-virtual/e2e/app/smooth-scroll/main.tsx
function getRandomInt (line 5) | function getRandomInt(min: number, max: number) {
FILE: packages/react-virtual/e2e/app/stale-index/main.tsx
type Item (line 12) | interface Item {
function makeItems (line 17) | function makeItems(count: number): Array<Item> {
FILE: packages/react-virtual/playwright.config.ts
constant PORT (line 3) | const PORT = 5173
FILE: packages/react-virtual/src/index.tsx
type ReactVirtualizerOptions (line 19) | type ReactVirtualizerOptions<
function useVirtualizerBase (line 26) | function useVirtualizerBase<
function useVirtualizer (line 67) | function useVirtualizer<
function useWindowVirtualizer (line 84) | function useWindowVirtualizer<TItemElement extends Element>(
FILE: packages/react-virtual/tests/index.test.tsx
type ListProps (line 22) | interface ListProps {
function List (line 32) | function List({
FILE: packages/solid-virtual/src/index.tsx
function createVirtualizerBase (line 23) | function createVirtualizerBase<
function createVirtualizer (line 90) | function createVirtualizer<
function createWindowVirtualizer (line 111) | function createWindowVirtualizer<TItemElement extends Element>(
FILE: packages/svelte-virtual/src/index.ts
type SvelteVirtualizer (line 16) | type SvelteVirtualizer<
function createVirtualizerBase (line 25) | function createVirtualizerBase<
function createVirtualizer (line 73) | function createVirtualizer<
function createWindowVirtualizer (line 90) | function createWindowVirtualizer<TItemElement extends Element>(
FILE: packages/virtual-core/src/index.ts
type ScrollDirection (line 7) | type ScrollDirection = 'forward' | 'backward'
type ScrollAlignment (line 9) | type ScrollAlignment = 'start' | 'center' | 'end' | 'auto'
type ScrollBehavior (line 11) | type ScrollBehavior = 'auto' | 'smooth' | 'instant'
type ScrollToOptions (line 13) | interface ScrollToOptions {
type ScrollToOffsetOptions (line 18) | type ScrollToOffsetOptions = ScrollToOptions
type ScrollToIndexOptions (line 20) | type ScrollToIndexOptions = ScrollToOptions
type Range (line 22) | interface Range {
type Key (line 29) | type Key = number | string | bigint
type VirtualItem (line 31) | interface VirtualItem {
type Rect (line 40) | interface Rect {
type ObserveOffsetCallBack (line 144) | type ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void
type VirtualizerOptions (line 295) | interface VirtualizerOptions<
type ScrollState (line 351) | type ScrollState = {
class Virtualizer (line 367) | class Virtualizer<
method constructor (line 446) | constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {
method scheduleScrollReconcile (line 588) | private scheduleScrollReconcile() {
method reconcileScroll (line 599) | private reconcileScroll() {
function calculateRange (line 1331) | function calculateRange({
FILE: packages/virtual-core/src/utils.ts
type NoInfer (line 1) | type NoInfer<A extends any> = [A][A extends any ? 0 : never]
type PartialKeys (line 3) | type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
function memo (line 5) | function memo<TDeps extends ReadonlyArray<any>, TResult>(
function notUndefined (line 84) | function notUndefined<T>(value: T | undefined, msg?: string): T {
FILE: packages/virtual-core/tests/index.test.ts
function createMockEnvironment (line 236) | function createMockEnvironment() {
function createVirtualizer (line 276) | function createVirtualizer(
FILE: packages/vue-virtual/src/index.ts
type MaybeRef (line 23) | type MaybeRef<T> = T | Ref<T>
function useVirtualizerBase (line 25) | function useVirtualizerBase<
function useVirtualizer (line 72) | function useVirtualizer<
function useWindowVirtualizer (line 93) | function useWindowVirtualizer<TItemElement extends Element>(
FILE: scripts/verify-links.ts
function isRelativeLink (line 14) | function isRelativeLink(link: string) {
function stripExtension (line 26) | function stripExtension(p: string): string {
function relativeLinkExists (line 30) | function relativeLinkExists(link: string, file: string): boolean {
function verifyMarkdownLinks (line 88) | async function verifyMarkdownLinks() {
Condensed preview — 515 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (631K chars).
[
{
"path": ".changeset/config.json",
"chars": 449,
"preview": "{\n \"$schema\": \"https://unpkg.com/@changesets/config@3.1.2/schema.json\",\n \"changelog\": [\n \"@svitejs/changesets-chang"
},
{
"path": ".gitattributes",
"chars": 73,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto eol=lf\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 22,
"preview": "github: tannerlinsley\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 5800,
"preview": "name: 🐛 Bug Report\ndescription: Report a reproducible bug or regression\nbody:\n - type: markdown\n attributes:\n v"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 448,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 🤔 Feature Requests & Questions\n url: https://github.com/TanStack"
},
{
"path": ".github/pull_request_template.md",
"chars": 532,
"preview": "## 🎯 Changes\n\n<!-- What changes are made in this PR? Describe the change and its motivation. -->\n\n## ✅ Checklist\n\n- [ ] "
},
{
"path": ".github/renovate.json",
"chars": 564,
"preview": "{\n \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n \"configMigration\": true,\n \"extends\": [\n \"confi"
},
{
"path": ".github/workflows/autofix.yml",
"chars": 699,
"preview": "name: autofix.ci # needed to securely identify the workflow\n\non:\n pull_request:\n push:\n branches: [main, alpha, bet"
},
{
"path": ".github/workflows/pr.yml",
"chars": 1766,
"preview": "name: PR\n\non:\n pull_request:\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.event.number || github.ref }}\n c"
},
{
"path": ".github/workflows/release.yml",
"chars": 1313,
"preview": "name: Release\n\non:\n push:\n branches: [main, alpha, beta]\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.ev"
},
{
"path": ".gitignore",
"chars": 605,
"preview": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\npackage-lock.js"
},
{
"path": ".npmrc",
"chars": 16,
"preview": "provenance=true\n"
},
{
"path": ".nvmrc",
"chars": 7,
"preview": "24.8.0\n"
},
{
"path": ".prettierignore",
"chars": 121,
"preview": "**/.next\n**/.nx/cache\n**/.svelte-kit\n**/build\n**/coverage\n**/dist\n**/docs\n**/codemods/**/__testfixtures__\npnpm-lock.yaml"
},
{
"path": "CONTRIBUTING.md",
"chars": 6215,
"preview": "# Contributing\n\n## Questions\n\nIf you have questions about implementation details, help or support, then please use our d"
},
{
"path": "LICENSE",
"chars": 1079,
"preview": "MIT License\n\nCopyright (c) 2021-present Tanner Linsley\n\nPermission is hereby granted, free of charge, to any person obta"
},
{
"path": "README.md",
"chars": 4869,
"preview": "<div align=\"center\">\n <img src=\"./media/header_virtual.png\" alt=\"Tanstack Virtual\">\n</div>\n\n<br />\n\n<div align=\"center\""
},
{
"path": "docs/api/virtual-item.md",
"chars": 1780,
"preview": "---\ntitle: VirtualItem\n---\n\nThe `VirtualItem` object represents a single item returned by the virtualizer. It contains i"
},
{
"path": "docs/api/virtualizer.md",
"chars": 16645,
"preview": "---\ntitle: Virtualizer\n---\n\nThe `Virtualizer` class is the core of TanStack Virtual. Virtualizer instances are usually c"
},
{
"path": "docs/config.json",
"chars": 6459,
"preview": "{\n \"$schema\": \"https://raw.githubusercontent.com/TanStack/tanstack.com/main/tanstack-docs-config.schema.json\",\n \"docSe"
},
{
"path": "docs/framework/angular/angular-virtual.md",
"chars": 1083,
"preview": "---\ntitle: Angular Virtual\n---\n\nThe `@tanstack/angular-virtual` adapter is a wrapper around the core virtual logic.\n\n## "
},
{
"path": "docs/framework/lit/lit-virtual.md",
"chars": 1148,
"preview": "---\ntitle: Lit Virtual\n---\n\nThe `@tanstack/lit-virtual` adapter is a wrapper around the core virtual logic.\n\n## `createV"
},
{
"path": "docs/framework/react/react-virtual.md",
"chars": 2620,
"preview": "---\ntitle: React Virtual\n---\n\nThe `@tanstack/react-virtual` adapter is a wrapper around the core virtual logic.\n\n## `use"
},
{
"path": "docs/framework/solid/solid-virtual.md",
"chars": 958,
"preview": "---\ntitle: Solid Virtual\n---\n\nThe `@tanstack/solid-virtual` adapter is a wrapper around the core virtual logic.\n\n## `cre"
},
{
"path": "docs/framework/svelte/svelte-virtual.md",
"chars": 960,
"preview": "---\ntitle: Svelte Virtual\n---\n\nThe `@tanstack/svelte-virtual` adapter is a wrapper around the core virtual logic.\n\n## `c"
},
{
"path": "docs/framework/vue/vue-virtual.md",
"chars": 942,
"preview": "---\ntitle: Vue Virtual\n---\n\nThe `@tanstack/vue-virtual` adapter is a wrapper around the core virtual logic.\n\n## `useVirt"
},
{
"path": "docs/installation.md",
"chars": 655,
"preview": "---\ntitle: Installation\n---\n\nBefore we dig in to the API, let's get you set up!\n\nInstall your TanStack Virtual adapter a"
},
{
"path": "docs/introduction.md",
"chars": 2245,
"preview": "---\ntitle: Introduction\n---\n\nTanStack Virtual is a headless UI utility for virtualizing long lists of elements in JS/TS,"
},
{
"path": "eslint.config.js",
"chars": 371,
"preview": "// @ts-check\n\nimport { tanstackConfig } from '@tanstack/eslint-config'\n\nexport default [\n ...tanstackConfig,\n {\n na"
},
{
"path": "examples/angular/dynamic/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/dynamic/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/dynamic/README.md",
"chars": 1092,
"preview": "# @tanstack/virtualExampleAngularDynamic\n\nThis project was generated with [Angular CLI](https://github.com/angular/angul"
},
{
"path": "examples/angular/dynamic/angular.json",
"chars": 1911,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"cli\": {\n \"packageManager\": \"p"
},
{
"path": "examples/angular/dynamic/package.json",
"chars": 890,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-dynamic\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\":"
},
{
"path": "examples/angular/dynamic/src/app/app.component.ts",
"chars": 838,
"preview": "import { Component } from '@angular/core'\nimport { RouterLink, RouterOutlet } from '@angular/router'\n\n@Component({\n sel"
},
{
"path": "examples/angular/dynamic/src/app/app.config.ts",
"chars": 224,
"preview": "import { ApplicationConfig } from '@angular/core'\nimport { provideRouter } from '@angular/router'\n\nimport { routes } fro"
},
{
"path": "examples/angular/dynamic/src/app/app.routes.ts",
"chars": 677,
"preview": "import { Routes } from '@angular/router'\nimport { RowVirtualizerDynamic } from './row-virtualizer-dynamic.component'\nimp"
},
{
"path": "examples/angular/dynamic/src/app/column-virtualizer-dynamic.component.ts",
"chars": 1983,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n viewChild,\n viewChildren,\n} from '@angular/c"
},
{
"path": "examples/angular/dynamic/src/app/grid-virtualizer-dynamic.component.ts",
"chars": 3416,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n afterNextRender,\n computed,\n effect,\n signal,\n view"
},
{
"path": "examples/angular/dynamic/src/app/row-virtualizer-dynamic-window.component.ts",
"chars": 2290,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n afterNextRender,\n effect,\n signal,\n untracked,\n vie"
},
{
"path": "examples/angular/dynamic/src/app/row-virtualizer-dynamic.component.ts",
"chars": 2496,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n viewChild,\n viewChildren,\n} from '@angular/c"
},
{
"path": "examples/angular/dynamic/src/app/utils.ts",
"chars": 958,
"preview": "import { faker } from '@faker-js/faker'\n\nexport const generateRandomNumber = (min: number, max: number) =>\n faker.numbe"
},
{
"path": "examples/angular/dynamic/src/index.html",
"chars": 352,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularDynamic"
},
{
"path": "examples/angular/dynamic/src/main.ts",
"chars": 243,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { appConfig } from './app/app.config'\nimport { A"
},
{
"path": "examples/angular/dynamic/src/styles.css",
"chars": 327,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/dynamic/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/dynamic/tsconfig.json",
"chars": 911,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/fixed/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/fixed/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/fixed/README.md",
"chars": 1090,
"preview": "# @tanstack/virtualExampleAngularFixed\n\nThis project was generated with [Angular CLI](https://github.com/angular/angular"
},
{
"path": "examples/angular/fixed/angular.json",
"chars": 1901,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/fixed/package.json",
"chars": 855,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-fixed\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\": \""
},
{
"path": "examples/angular/fixed/src/app/app.component.ts",
"chars": 813,
"preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\nimport { ColumnVirtualizerFixed } from './column-vir"
},
{
"path": "examples/angular/fixed/src/app/column-virtualizer-fixed.component.ts",
"chars": 1445,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n viewChild,\n} from '@angular/core'\nimport { injectVirtua"
},
{
"path": "examples/angular/fixed/src/app/grid-virtualizer-fixed.component.ts",
"chars": 2285,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n viewChild,\n} from '@angular/core'\nimport { injectVirtua"
},
{
"path": "examples/angular/fixed/src/app/row-virtualizer-fixed.component.ts",
"chars": 1413,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n viewChild,\n} from '@angular/core'\nimport { injectVirtua"
},
{
"path": "examples/angular/fixed/src/index.html",
"chars": 350,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularFixed</"
},
{
"path": "examples/angular/fixed/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/fixed/src/styles.css",
"chars": 393,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/fixed/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/fixed/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/infinite-scroll/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/infinite-scroll/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/infinite-scroll/README.md",
"chars": 1099,
"preview": "# @tanstack/virtualExampleAngularInfiniteScroll\n\nThis project was generated with [Angular CLI](https://github.com/angula"
},
{
"path": "examples/angular/infinite-scroll/angular.json",
"chars": 1951,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/infinite-scroll/package.json",
"chars": 919,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-infinite-scroll\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n "
},
{
"path": "examples/angular/infinite-scroll/src/app/app.component.ts",
"chars": 3673,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n effect,\n viewChild,\n} from '@angular/core'"
},
{
"path": "examples/angular/infinite-scroll/src/index.html",
"chars": 359,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularInfinit"
},
{
"path": "examples/angular/infinite-scroll/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/infinite-scroll/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/infinite-scroll/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/infinite-scroll/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/padding/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/padding/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/padding/README.md",
"chars": 1092,
"preview": "# @tanstack/virtualExampleAngularPadding\n\nThis project was generated with [Angular CLI](https://github.com/angular/angul"
},
{
"path": "examples/angular/padding/angular.json",
"chars": 1911,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/padding/package.json",
"chars": 857,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-padding\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\":"
},
{
"path": "examples/angular/padding/src/app/app.component.ts",
"chars": 1343,
"preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\nimport { ColumnVirtualizerPadding } from './column-v"
},
{
"path": "examples/angular/padding/src/app/column-virtualizer-padding.component.ts",
"chars": 1884,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n input,\n viewChild,\n viewChildren,\n} from '@"
},
{
"path": "examples/angular/padding/src/app/grid-virtualizer-padding.component.ts",
"chars": 3451,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n input,\n signal,\n viewChild,\n viewChildren,"
},
{
"path": "examples/angular/padding/src/app/row-virtualizer-padding.component.ts",
"chars": 1825,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n input,\n viewChild,\n viewChildren,\n} from '@"
},
{
"path": "examples/angular/padding/src/index.html",
"chars": 352,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularPadding"
},
{
"path": "examples/angular/padding/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/padding/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/padding/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/padding/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/smooth-scroll/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/smooth-scroll/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/smooth-scroll/README.md",
"chars": 1097,
"preview": "# @tanstack/virtualExampleAngularSmoothScroll\n\nThis project was generated with [Angular CLI](https://github.com/angular/"
},
{
"path": "examples/angular/smooth-scroll/angular.json",
"chars": 1941,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/smooth-scroll/package.json",
"chars": 863,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-smooth-scroll\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n "
},
{
"path": "examples/angular/smooth-scroll/src/app/app.component.ts",
"chars": 2814,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n signal,\n viewChild,\n} from '@angular/core'\nimport { el"
},
{
"path": "examples/angular/smooth-scroll/src/index.html",
"chars": 357,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularSmoothS"
},
{
"path": "examples/angular/smooth-scroll/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/smooth-scroll/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/smooth-scroll/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/smooth-scroll/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/sticky/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/sticky/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/sticky/README.md",
"chars": 1091,
"preview": "# @tanstack/virtualExampleAngularSticky\n\nThis project was generated with [Angular CLI](https://github.com/angular/angula"
},
{
"path": "examples/angular/sticky/angular.json",
"chars": 1906,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/sticky/package.json",
"chars": 889,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-sticky\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\": "
},
{
"path": "examples/angular/sticky/src/app/app.component.ts",
"chars": 2746,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n viewChild,\n} from '@angular/core'\nimport { "
},
{
"path": "examples/angular/sticky/src/index.html",
"chars": 351,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularSticky<"
},
{
"path": "examples/angular/sticky/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/sticky/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/sticky/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/sticky/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/table/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/table/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/table/README.md",
"chars": 1090,
"preview": "# @tanstack/virtualExampleAngularTable\n\nThis project was generated with [Angular CLI](https://github.com/angular/angular"
},
{
"path": "examples/angular/table/angular.json",
"chars": 1901,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/table/package.json",
"chars": 929,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-table\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\": \""
},
{
"path": "examples/angular/table/src/app/app.component.ts",
"chars": 5255,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n signal,\n viewChild,\n} from '@angular/core'"
},
{
"path": "examples/angular/table/src/app/make-data.ts",
"chars": 1089,
"preview": "import { faker } from '@faker-js/faker'\n\nexport type Person = {\n id: number\n firstName: string\n lastName: string\n ag"
},
{
"path": "examples/angular/table/src/index.html",
"chars": 350,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularTable</"
},
{
"path": "examples/angular/table/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/table/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/table/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/table/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/variable/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/variable/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/variable/README.md",
"chars": 1093,
"preview": "# @tanstack/virtualExampleAngularVariable\n\nThis project was generated with [Angular CLI](https://github.com/angular/angu"
},
{
"path": "examples/angular/variable/angular.json",
"chars": 1916,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/variable/package.json",
"chars": 858,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-variable\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\""
},
{
"path": "examples/angular/variable/src/app/app.component.ts",
"chars": 1128,
"preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\nimport { ColumnVirtualizerVariable } from './column-"
},
{
"path": "examples/angular/variable/src/app/column-virtualizer-variable.component.ts",
"chars": 1524,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n viewChild,\n} from '@angular/core'\nimport { inj"
},
{
"path": "examples/angular/variable/src/app/grid-virtualizer-variable.component.ts",
"chars": 2423,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n viewChild,\n} from '@angular/core'\nimport { inj"
},
{
"path": "examples/angular/variable/src/app/row-virtualizer-variable.component.ts",
"chars": 1500,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n viewChild,\n} from '@angular/core'\nimport { inj"
},
{
"path": "examples/angular/variable/src/index.html",
"chars": 353,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularVariabl"
},
{
"path": "examples/angular/variable/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/variable/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/variable/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/variable/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/angular/window/.devcontainer/devcontainer.json",
"chars": 89,
"preview": "{\n \"name\": \"Node.js\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:18\"\n}\n"
},
{
"path": "examples/angular/window/.gitignore",
"chars": 587,
"preview": "# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.\n\n# Comp"
},
{
"path": "examples/angular/window/README.md",
"chars": 1091,
"preview": "# @tanstack/virtualExampleAngularWindow\n\nThis project was generated with [Angular CLI](https://github.com/angular/angula"
},
{
"path": "examples/angular/window/angular.json",
"chars": 1906,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "examples/angular/window/package.json",
"chars": 856,
"preview": "{\n \"name\": \"@tanstack/virtual-example-angular-window\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"ng\": "
},
{
"path": "examples/angular/window/src/app/app.component.ts",
"chars": 1815,
"preview": "import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n viewChild,\n} from '@angular/core'\nimport { injectWindow"
},
{
"path": "examples/angular/window/src/index.html",
"chars": 351,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>@tanstack/virtualExampleAngularWindow<"
},
{
"path": "examples/angular/window/src/main.ts",
"chars": 187,
"preview": "import { bootstrapApplication } from '@angular/platform-browser'\nimport { AppComponent } from './app/app.component'\n\nboo"
},
{
"path": "examples/angular/window/src/styles.css",
"chars": 431,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/angular/window/tsconfig.app.json",
"chars": 247,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"extends\": \"./tsconfig.json\",\n \"compil"
},
{
"path": "examples/angular/window/tsconfig.json",
"chars": 839,
"preview": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n \"compileOnSave\": false,\n \"compilerOpti"
},
{
"path": "examples/lit/dynamic/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/lit/dynamic/README.md",
"chars": 95,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `npm`\n- `npm run start` or `npm run start`\n"
},
{
"path": "examples/lit/dynamic/index.html",
"chars": 288,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/lit/dynamic/package.json",
"chars": 461,
"preview": "{\n \"name\": \"tanstack-lit-virtual-example-dynamic\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vi"
},
{
"path": "examples/lit/dynamic/src/index.css",
"chars": 82,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n padding: 1rem;\n}\n"
},
{
"path": "examples/lit/dynamic/src/main.ts",
"chars": 10556,
"preview": "import { customElement, property } from 'lit/decorators.js'\nimport { Ref, createRef, ref } from 'lit/directives/ref.js'\n"
},
{
"path": "examples/lit/dynamic/tsconfig.json",
"chars": 286,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"outDir\": \"./build/types\",\n \"target\": \"ESNext\",\n \"module\": \"ESNe"
},
{
"path": "examples/lit/dynamic/vite.config.js",
"chars": 115,
"preview": "import { defineConfig } from 'vite'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n plugins: [],\n})\n"
},
{
"path": "examples/lit/fixed/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/lit/fixed/README.md",
"chars": 95,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `npm`\n- `npm run start` or `npm run start`\n"
},
{
"path": "examples/lit/fixed/index.html",
"chars": 288,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/lit/fixed/package.json",
"chars": 459,
"preview": "{\n \"name\": \"tanstack-lit-virtual-example-fixed\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite"
},
{
"path": "examples/lit/fixed/src/index.css",
"chars": 82,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n padding: 1rem;\n}\n"
},
{
"path": "examples/lit/fixed/src/main.ts",
"chars": 8609,
"preview": "import { customElement, property } from 'lit/decorators.js'\nimport { Ref, createRef, ref } from 'lit/directives/ref.js'\n"
},
{
"path": "examples/lit/fixed/tsconfig.json",
"chars": 286,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"outDir\": \"./build/types\",\n \"target\": \"ESNext\",\n \"module\": \"ESNe"
},
{
"path": "examples/lit/fixed/vite.config.js",
"chars": 115,
"preview": "import { defineConfig } from 'vite'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n plugins: [],\n})\n"
},
{
"path": "examples/react/dynamic/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/react/dynamic/README.md",
"chars": 95,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `npm`\n- `npm run start` or `npm run start`\n"
},
{
"path": "examples/react/dynamic/index.html",
"chars": 267,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/react/dynamic/package.json",
"chars": 559,
"preview": "{\n \"name\": \"tanstack-react-virtual-example-dynamic\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \""
},
{
"path": "examples/react/dynamic/src/index.css",
"chars": 241,
"preview": "*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n pad"
},
{
"path": "examples/react/dynamic/src/main.tsx",
"chars": 12154,
"preview": "import * as React from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { faker } from '@faker-js/faker'\n\nim"
},
{
"path": "examples/react/dynamic/tsconfig.json",
"chars": 572,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\""
},
{
"path": "examples/react/dynamic/vite.config.js",
"chars": 163,
"preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\n// https://vitejs.dev/config/\nexport defau"
},
{
"path": "examples/react/fixed/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/react/fixed/README.md",
"chars": 93,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `yarn`\n- `npm run start` or `yarn start`\n"
},
{
"path": "examples/react/fixed/index.html",
"chars": 267,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/react/fixed/package.json",
"chars": 524,
"preview": "{\n \"name\": \"tanstack-react-virtual-example-fixed\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vi"
},
{
"path": "examples/react/fixed/src/index.css",
"chars": 327,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n padding: 1rem;\n}\n\n.List {\n border: 1px solid #e6e4dc;\n"
},
{
"path": "examples/react/fixed/src/main.tsx",
"chars": 5590,
"preview": "import * as React from 'react'\nimport * as ReactDOM from 'react-dom/client'\n\nimport './index.css'\n\nimport { useVirtualiz"
},
{
"path": "examples/react/fixed/tsconfig.json",
"chars": 572,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\""
},
{
"path": "examples/react/fixed/vite.config.js",
"chars": 163,
"preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\n// https://vitejs.dev/config/\nexport defau"
},
{
"path": "examples/react/infinite-scroll/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/react/infinite-scroll/README.md",
"chars": 93,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `yarn`\n- `npm run start` or `yarn start`\n"
},
{
"path": "examples/react/infinite-scroll/index.html",
"chars": 372,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/react/infinite-scroll/package.json",
"chars": 543,
"preview": "{\n \"name\": \"tanstack-react-virtual-example-infinite-scroll\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n "
},
{
"path": "examples/react/infinite-scroll/src/index.css",
"chars": 327,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n padding: 1rem;\n}\n\n.List {\n border: 1px solid #e6e4dc;\n"
},
{
"path": "examples/react/infinite-scroll/src/main.tsx",
"chars": 4177,
"preview": "import React from 'react'\nimport ReactDOM from 'react-dom'\nimport {\n QueryClient,\n QueryClientProvider,\n useInfiniteQ"
},
{
"path": "examples/react/infinite-scroll/tsconfig.json",
"chars": 572,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\""
},
{
"path": "examples/react/infinite-scroll/vite.config.js",
"chars": 133,
"preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n plugins: ["
},
{
"path": "examples/react/padding/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/react/padding/README.md",
"chars": 93,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `yarn`\n- `npm run start` or `yarn start`\n"
},
{
"path": "examples/react/padding/index.html",
"chars": 372,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/react/padding/package.json",
"chars": 495,
"preview": "{\n \"name\": \"tanstack-react-virtual-example-padding\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \""
},
{
"path": "examples/react/padding/src/index.css",
"chars": 327,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\nbody {\n padding: 1rem;\n}\n\n.List {\n border: 1px solid #e6e4dc;\n"
},
{
"path": "examples/react/padding/src/main.tsx",
"chars": 7390,
"preview": "import React from 'react'\nimport ReactDOM from 'react-dom'\n\nimport './index.css'\n\nimport { useVirtualizer } from '@tanst"
},
{
"path": "examples/react/padding/tsconfig.json",
"chars": 572,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\""
},
{
"path": "examples/react/padding/vite.config.js",
"chars": 133,
"preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n plugins: ["
},
{
"path": "examples/react/scroll-padding/.gitignore",
"chars": 45,
"preview": "node_modules\n.DS_Store\ndist\ndist-ssr\n*.local\n"
},
{
"path": "examples/react/scroll-padding/README.md",
"chars": 93,
"preview": "# Example\n\nTo run this example:\n\n- `npm install` or `yarn`\n- `npm run start` or `yarn start`\n"
},
{
"path": "examples/react/scroll-padding/index.html",
"chars": 372,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/react/scroll-padding/package.json",
"chars": 537,
"preview": "{\n \"name\": \"tanstack-react-virtual-example-scroll-padding\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \""
},
{
"path": "examples/react/scroll-padding/src/index.css",
"chars": 664,
"preview": "html {\n font-family: sans-serif;\n font-size: 14px;\n}\n\n.List table {\n background-color: #fff;\n border: 1px solid #e6e"
},
{
"path": "examples/react/scroll-padding/src/main.tsx",
"chars": 2716,
"preview": "import React from 'react'\nimport ReactDOM from 'react-dom'\n\nimport './index.css'\n\nimport { useMeasure } from '@react-hoo"
},
{
"path": "examples/react/scroll-padding/tsconfig.json",
"chars": 572,
"preview": "{\n \"composite\": true,\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"lib\": [\""
}
]
// ... and 315 more files (download for full content)
About this extraction
This page contains the full source code of the TanStack/virtual GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 515 files (550.6 KB), approximately 163.6k tokens, and a symbol index with 169 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.