{"id":50469983,"url":"https://github.com/theryansmee/ngx-virtual-grid","last_synced_at":"2026-06-11T20:02:40.474Z","repository":{"id":357326762,"uuid":"1235927958","full_name":"theryansmee/ngx-virtual-grid","owner":"theryansmee","description":"A responsive virtual-scrolling grid for Angular with infinite scroll. CSS Grid layout, auto-measured dimensions.","archived":false,"fork":false,"pushed_at":"2026-06-09T19:40:50.000Z","size":1310,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T21:15:06.911Z","etag":null,"topics":["angular","angular-component","angular-library","css-grid","infinite-scroll","ngx","responsive-grid","typescript","virtual-grid","virtual-scroll"],"latest_commit_sha":null,"homepage":"https://theryansmee.github.io/ngx-virtual-grid/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/theryansmee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-11T19:41:18.000Z","updated_at":"2026-06-09T19:41:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/theryansmee/ngx-virtual-grid","commit_stats":null,"previous_names":["theryansmee/ngx-virtual-grid"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/theryansmee/ngx-virtual-grid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theryansmee%2Fngx-virtual-grid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theryansmee%2Fngx-virtual-grid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theryansmee%2Fngx-virtual-grid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theryansmee%2Fngx-virtual-grid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theryansmee","download_url":"https://codeload.github.com/theryansmee/ngx-virtual-grid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theryansmee%2Fngx-virtual-grid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34215254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-component","angular-library","css-grid","infinite-scroll","ngx","responsive-grid","typescript","virtual-grid","virtual-scroll"],"created_at":"2026-06-01T10:00:22.219Z","updated_at":"2026-06-11T20:02:40.468Z","avatar_url":"https://github.com/theryansmee.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Scroll"],"readme":"# ngx-virtual-grid\n\n[![npm version](https://img.shields.io/npm/v/@theryansmee/ngx-virtual-grid.svg)](https://www.npmjs.com/package/@theryansmee/ngx-virtual-grid)\n[![npm downloads](https://img.shields.io/npm/dw/@theryansmee/ngx-virtual-grid.svg)](https://www.npmjs.com/package/@theryansmee/ngx-virtual-grid)\n[![license](https://img.shields.io/npm/l/@theryansmee/ngx-virtual-grid.svg)](https://github.com/theryansmee/ngx-virtual-grid/blob/main/LICENSE)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/@theryansmee/ngx-virtual-grid)](https://bundlephobia.com/package/@theryansmee/ngx-virtual-grid)\n\nA responsive virtual-scrolling grid for Angular with built-in infinite scroll. Uses CSS Grid for layout, auto-measures item dimensions, and only renders what's visible.\n\n[Live Demo](https://theryansmee.github.io/ngx-virtual-grid/) | [GitHub](https://github.com/theryansmee/ngx-virtual-grid) | [npm](https://www.npmjs.com/package/@theryansmee/ngx-virtual-grid)\n\n## Why ngx-virtual-grid?\n\nAngular CDK's `cdk-virtual-scroll-viewport` only handles single-column lists. If you need a responsive multi-column grid with virtual scrolling, you're on your own.\n\nngx-virtual-grid gives you a real CSS Grid that only renders visible items. You control the layout with standard `grid-template-columns` and `gap` - the library reads the computed grid to figure out column count and row height automatically. No config objects, no pixel math.\n\nIt also works as a single-column virtual list - just set `grid-template-columns: 1fr`.\n\n## Features\n\n- Virtual scrolling with CSS Grid layout\n- Auto-measures item dimensions from the first rendered row\n- Responsive - adapts to column count changes via CSS\n- Infinite scroll with configurable threshold\n- Works as a grid or a single-column list\n- Works with both zoned and zoneless Angular apps\n- SSR-safe with prerendering support\n\n## Installation\n\n```bash\nnpm install @theryansmee/ngx-virtual-grid\n```\n\n```bash\nyarn add @theryansmee/ngx-virtual-grid\n```\n\n```bash\npnpm add @theryansmee/ngx-virtual-grid\n```\n\n## Angular Version Support\n\nEach Angular major version is maintained on its own branch:\n\n| Branch | Angular | Library | npm tag |\n|---|---|---|---|\n| `angular/14` | 14.x | 14.x.x | `angular14` |\n| `angular/15` | 15.x | 15.x.x | `angular15` |\n| `angular/16` | 16.x | 16.x.x | `angular16` |\n| `angular/17` | 17.x | 17.x.x | `angular17` |\n| `angular/18` | 18.x | 18.x.x | `angular18` |\n| `angular/19` | 19.x | 19.x.x | `angular19` |\n| `angular/20` | 20.x | 20.x.x | `angular20` |\n| `angular/21` | 21.x | 21.x.x | `angular21` |\n| `angular/22` | 22.x | 22.x.x | `latest` |\n\nThe `main` branch tracks the latest stable version.\n\n## Usage\n\nImport the component and directive directly (standalone):\n\n```typescript\nimport { Component } from '@angular/core';\nimport { NgxVirtualGridComponent, VirtualGridItemDirective } from '@theryansmee/ngx-virtual-grid';\n\n@Component({\n  selector: 'app-example',\n  imports: [NgxVirtualGridComponent, VirtualGridItemDirective],\n  template: `\n    \u003cngx-virtual-grid\n      [items]=\"items\"\n      [bufferSize]=\"3\"\n      [loadMoreThreshold]=\"0.8\"\n      (loadMore)=\"onLoadMore()\"\u003e\n\n      \u003cng-template ngxVirtualGridItem let-item let-index=\"index\"\u003e\n        \u003cdiv class=\"card\"\u003e{{ item.name }}\u003c/div\u003e\n      \u003c/ng-template\u003e\n    \u003c/ngx-virtual-grid\u003e\n  `,\n  styles: [`\n    ngx-virtual-grid {\n      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n      gap: 16px;\n    }\n  `],\n})\nexport class ExampleComponent {\n  items: any[] = [];\n\n  onLoadMore(): void {\n    // Load more items...\n  }\n}\n```\n\n### Grid or list - your call\n\nThe layout is controlled entirely by CSS. The component is a CSS Grid container, so you just set `grid-template-columns` on it like you would any grid.\n\n**Responsive multi-column grid:**\n\n```css\nngx-virtual-grid {\n  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n  gap: 16px;\n}\n```\n\n**Fixed 3-column grid:**\n\n```css\nngx-virtual-grid {\n  grid-template-columns: repeat(3, 1fr);\n  gap: 16px;\n}\n```\n\n**Single-column list:**\n\n```css\nngx-virtual-grid {\n  grid-template-columns: 1fr;\n  gap: 8px;\n}\n```\n\nSame component, same API. The library figures out the column count and row height from your CSS automatically.\n\n### Drop it anywhere on the page\n\nYou don't need to wrap your entire page in this component. It works alongside other content - just put it wherever you need a virtual list or grid:\n\n```html\n\u003ch1\u003eMy Dashboard\u003c/h1\u003e\n\u003cp\u003eSome intro text, a navbar, whatever you want up here.\u003c/p\u003e\n\n\u003cngx-virtual-grid [items]=\"products\" (loadMore)=\"loadMoreProducts()\"\u003e\n  \u003cng-template ngxVirtualGridItem let-product\u003e\n    \u003capp-product-card [product]=\"product\" /\u003e\n  \u003c/ng-template\u003e\n\u003c/ngx-virtual-grid\u003e\n\n\u003cfooter\u003eStill works down here too.\u003c/footer\u003e\n```\n\nBy default it listens for scroll events on `window`, so it just works as part of your normal page scroll. No need for a fixed-height wrapper or any special container setup.\n\n### Custom scroll container\n\nIf you do want to put it inside a scrollable container (like a panel or sidebar), pass the container element as `scrollParent`:\n\n```html\n\u003cdiv #scrollContainer style=\"height: 600px; overflow-y: auto;\"\u003e\n  \u003cngx-virtual-grid [items]=\"items\" [scrollParent]=\"scrollContainer\"\u003e\n    \u003cng-template ngxVirtualGridItem let-item\u003e\n      \u003cdiv class=\"card\"\u003e{{ item.name }}\u003c/div\u003e\n    \u003c/ng-template\u003e\n  \u003c/ngx-virtual-grid\u003e\n\u003c/div\u003e\n```\n\n## API\n\n### Inputs\n\n| Input | Type | Default | Description |\n|---|---|---|---|\n| `items` | `unknown[]` | `[]` | Array of data items to render |\n| `bufferSize` | `number` | `3` | Number of extra rows to render above and below the viewport |\n| `loadMoreThreshold` | `number` | `0.8` | Scroll ratio (0-1) at which the `loadMore` event fires |\n| `scrollParent` | `HTMLElement \\| null` | `null` | Custom scroll container. Uses `window` if `null` |\n\n### Outputs\n\n| Output | Type | Description |\n|---|---|---|\n| `loadMore` | `void` | Emits when the scroll position crosses the `loadMoreThreshold`. Resets when the `items` array length changes. |\n\n### Methods\n\n| Method | Description |\n|---|---|\n| `scrollToIndex(index: number)` | Scroll to bring the item at `index` into view |\n| `scrollToOffset(px: number)` | Scroll to an absolute pixel offset within the grid |\n| `refresh()` | Re-measure dimensions and recalculate layout |\n\n### Template context\n\nThe `ngxVirtualGridItem` template receives:\n\n| Variable | Type | Description |\n|---|---|---|\n| `$implicit` | `T` | The data item |\n| `index` | `number` | The item's index in the original array |\n\n### Zoneless apps\n\nThe library works with both zoned and zoneless Angular apps. In zoneless mode, the `loadMore` output emits from a raw scroll event listener. If your handler modifies component state, use signals so the view updates:\n\n```typescript\nitems = signal\u003cItem[]\u003e([]);\n\nonLoadMore(): void {\n  // Signal write triggers change detection in zoneless mode\n  this.items.update(current =\u003e [...current, ...newItems]);\n}\n```\n\n## Prerequisites\n\n- Node.js 22.22+\n- pnpm 11+\n- Angular 22.x\n\n## Development\n\n```bash\n# Install dependencies\npnpm install\n\n# Build the library\npnpm run build:lib\n\n# Start the demo app (builds library first, then serves demo)\npnpm start\n```\n\nThe demo app runs at `http://localhost:4200/`.\n\n### Available scripts\n\n| Script | Description |\n|---|---|\n| `pnpm run build:lib` | Build the library for production |\n| `pnpm run build:demo` | Build the demo application |\n| `pnpm start` | Build library + serve demo app |\n| `pnpm test` | Run library unit tests (watch mode) |\n| `pnpm run test:ci` | Run library unit tests (single run) |\n| `pnpm run lint` | Lint all projects |\n| `pnpm run lint:fix` | Lint and auto-fix all projects |\n\n## Publishing\n\n```bash\npnpm run build:lib\ncd dist/ngx-virtual-grid\npnpm publish\n```\n\nWhen publishing older Angular version branches, use the version-specific tag so it doesn't become `latest`:\n\n```bash\npnpm publish --tag angular21\n```\n\n## Contributing\n\n1. Branch off the appropriate `angular/*` branch for your target Angular version\n2. Follow the existing code style (tabs, explicit types, explicit accessibility modifiers)\n3. Add unit tests for new functionality\n4. Ensure `pnpm run lint` and `pnpm run test:ci` pass before opening a PR\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheryansmee%2Fngx-virtual-grid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheryansmee%2Fngx-virtual-grid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheryansmee%2Fngx-virtual-grid/lists"}