{"id":51377225,"url":"https://github.com/ceriousdevtech/ngx-cerious-scroll","last_synced_at":"2026-07-05T21:00:34.398Z","repository":{"id":361883532,"uuid":"1147079022","full_name":"ceriousdevtech/ngx-cerious-scroll","owner":"ceriousdevtech","description":"Angular implementation for Cerious-Scroll","archived":false,"fork":false,"pushed_at":"2026-06-12T04:52:43.000Z","size":645,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T06:15:52.980Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ceriousdevtech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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-02-01T06:38:42.000Z","updated_at":"2026-06-12T04:52:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ceriousdevtech/ngx-cerious-scroll","commit_stats":null,"previous_names":["ceriousdevtech/ngx-cerious-scroll"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ceriousdevtech/ngx-cerious-scroll","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceriousdevtech%2Fngx-cerious-scroll","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceriousdevtech%2Fngx-cerious-scroll/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceriousdevtech%2Fngx-cerious-scroll/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceriousdevtech%2Fngx-cerious-scroll/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ceriousdevtech","download_url":"https://codeload.github.com/ceriousdevtech/ngx-cerious-scroll/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceriousdevtech%2Fngx-cerious-scroll/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35168795,"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-07-05T02:00:06.290Z","response_time":100,"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":[],"created_at":"2026-07-03T14:00:27.947Z","updated_at":"2026-07-05T21:00:34.392Z","avatar_url":"https://github.com/ceriousdevtech.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Scroll"],"readme":"# @ceriousdevtech/ngx-cerious-scroll\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Live Demo](https://img.shields.io/badge/demo-live-brightgreen)](https://ceriousdevtech.github.io/ngx-cerious-scroll/)\n\n**Angular bindings for [Cerious Scroll™](https://www.npmjs.com/package/@ceriousdevtech/cerious-scroll)** — high-performance virtual scrolling with **O(1) memory**, consistent **60 FPS+**, and **native variable-height support with no height estimation**.\n\nRows are rendered into the engine's own measured containers via Angular's `EmbeddedViewRef` and committed synchronously, so every row's real height is measured (never estimated) — exactly the guarantee that makes CeriousScroll precise. Because rows stay in your Angular tree, **DI, pipes, and structural directives work normally** inside each row.\n\n---\n\n## Installation\n\n```bash\nnpm install @ceriousdevtech/ngx-cerious-scroll @ceriousdevtech/cerious-scroll\n```\n\n`@angular/core` and `@angular/common` (\u003e= 16) are peer dependencies.\n\n---\n\n## Demo\n\n**[Live demo →](https://ceriousdevtech.github.io/ngx-cerious-scroll/)** — 100,000 rows, fixed/variable-height toggle, imperative jump-to-row, and live viewport stats.\n\nTo run locally:\n\n```bash\nnpm install\nnpm run build    # build the library\nnpm start        # dev server with HMR (http://localhost:4300/)\n```\n\nThe demo imports the wrapper by its package name, aliased to the built library,\nso rebuild the library after editing `projects/ngx-cerious-scroll/src/`.\n\n---\n\n## Quick start (component)\n\nGive the host a height; provide `items` and an `\u003cng-template ceriousScrollItem\u003e`.\n\n```ts\nimport { Component } from '@angular/core';\nimport {\n  CeriousScrollComponent,\n  CeriousScrollItemTemplateDirective,\n} from '@ceriousdevtech/ngx-cerious-scroll';\n\n@Component({\n  standalone: true,\n  imports: [CeriousScrollComponent, CeriousScrollItemTemplateDirective],\n  template: `\n    \u003ccerious-scroll [items]=\"items\" style=\"height: 480px\"\u003e\n      \u003cng-template ceriousScrollItem let-item let-index=\"index\"\u003e\n        \u003cdiv class=\"row\"\u003e{{ index }} — {{ item.name }}\u003c/div\u003e\n      \u003c/ng-template\u003e\n    \u003c/cerious-scroll\u003e\n  `,\n})\nexport class List {\n  items = Array.from({ length: 1_000_000 }, (_, i) =\u003e ({ id: i, name: `Item ${i}` }));\n}\n```\n\nVariable heights need no configuration — just render rows of whatever height; the\nengine measures each one.\n\n### Without a full array (huge / sparse data)\n\n```html\n\u003ccerious-scroll\n  [totalElements]=\"100_000_000\"\n  [getItem]=\"loadRow\"\n  style=\"height: 600px\"\n\u003e\n  \u003cng-template ceriousScrollItem let-item let-index=\"index\"\u003e\n    \u003capp-row [data]=\"item\" [index]=\"index\" /\u003e\n  \u003c/ng-template\u003e\n\u003c/cerious-scroll\u003e\n```\n\n---\n\n## Directive\n\n`[ceriousScroll]` gives you full control on any host element. Pass a\n`TemplateRef` via `[ceriousScrollItemTemplate]`; the directive renders rows\nimperatively into the engine's measured containers.\n\n```ts\nimport { Component, TemplateRef, ViewChild } from '@angular/core';\nimport { CeriousScrollDirective } from '@ceriousdevtech/ngx-cerious-scroll';\n\n@Component({\n  standalone: true,\n  imports: [CeriousScrollDirective],\n  template: `\n    \u003cng-template #row let-item let-index=\"index\"\u003e\n      \u003cdiv class=\"row\"\u003e{{ index }} — {{ item.name }}\u003c/div\u003e\n    \u003c/ng-template\u003e\n\n    \u003cdiv\n      ceriousScroll\n      [ceriousScrollItems]=\"items\"\n      [ceriousScrollItemTemplate]=\"row\"\n      style=\"height: 480px; position: relative; overflow: hidden\"\n    \u003e\u003c/div\u003e\n  `,\n})\nexport class List {\n  @ViewChild('row', { static: true }) row!: TemplateRef\u003cany\u003e;\n  items = /* ... */;\n}\n```\n\n---\n\n## Component inputs\n\n| Input | Type | Description |\n| --- | --- | --- |\n| `items` | `readonly TItem[]` | Optional data array. `totalElements` defaults to `items.length`. |\n| `totalElements` | `number` | Total item count. Required if `items` is omitted. |\n| `getItem` | `(index) =\u003e TItem` | Lazy item getter for large/sparse datasets. |\n| `itemTemplate` | `TemplateRef\u003c{ $implicit, index }\u003e` | Row template. Alternative to projecting `\u003cng-template ceriousScrollItem\u003e`. |\n| `headerTemplate` | `TemplateRef` | Table mode only. `\u003ctr\u003e` of `\u003cth\u003e`s rendered into the engine's `\u003cthead\u003e` (see [Table layout](#table-layout)). |\n| `options` | `CeriousScrollOptions` | Engine options (keyboard/touch/wheel/scrollbar/`layout`/etc.). Read once at creation. |\n| `autoRender` | `boolean` | Re-render on scroll/resize/data changes. Default `true`. |\n\nThe row is provided by the projected `\u003cng-template ceriousScrollItem let-item let-index=\"index\"\u003e` or the `itemTemplate` input. Apply `class` / `style` directly to `\u003ccerious-scroll\u003e` — it's a block-level host (set a height!).\n\n### Outputs\n\n| Output | Payload | Description |\n| --- | --- | --- |\n| `viewportChange` | `CeriousViewportChangeDetail` | Normalized viewport-change (wheel/touch/keyboard/scrollbar). |\n| `measuredViewport` | `MeasuredViewportRange` | Measured range after each render pass. |\n| `scrollerReady` | `CeriousScroll` | The underlying engine instance, once ready. |\n\n### Imperative API (via template reference)\n\n```html\n\u003ccerious-scroll #scroll [items]=\"items\"\u003e…\u003c/cerious-scroll\u003e\n```\n\n```ts\n@ViewChild(CeriousScrollDirective) scroll!: CeriousScrollDirective;\n// scroll.jumpToElement(500);\n// scroll.scrollToPercentage(50);\n// scroll.reset();\n// scroll.render();\n// scroll.recalculate();           // drop cached heights + re-measure (see Notes)\n// scroll.hostRef?.scroller;       // the raw engine\n```\n\n---\n\n## Table layout\n\nPass `[ceriousScrollOptions]=\"{ layout: 'table' }\"` to render real `\u003ctable\u003e` / `\u003ctr\u003e` / `\u003ctd\u003e` rows with a frozen header and native column alignment. The row template returns the row's `\u003ctd\u003e` cells; `[ceriousScrollHeaderTemplate]` provides the `\u003cthead\u003e` row (it updates via change detection):\n\n```html\n\u003cdiv\n  class=\"my-scroll\"\n  ceriousScroll\n  [ceriousScrollTotalElements]=\"100000\"\n  [ceriousScrollGetItem]=\"getItem\"\n  [ceriousScrollItemTemplate]=\"rowTpl\"\n  [ceriousScrollHeaderTemplate]=\"headerTpl\"\n  [ceriousScrollOptions]=\"{ layout: 'table', table: { tableClassName: 'my-table', autoSizeColumns: true } }\"\n\u003e\u003c/div\u003e\n\n\u003cng-template #headerTpl\u003e\n  \u003ctr\u003e\n    @for (c of columns; track c.key) { \u003cth\u003e{{ c.label }}\u003c/th\u003e }\n  \u003c/tr\u003e\n\u003c/ng-template\u003e\n\n\u003c!-- Row template roots must be \u003ctd\u003es (no structural directive at the root). --\u003e\n\u003cng-template #rowTpl let-index\u003e\n  \u003ctd\u003e{{ row(index).id }}\u003c/td\u003e\n  \u003ctd\u003e{{ row(index).name }}\u003c/td\u003e\n  \u003ctd\u003e{{ row(index).email }}\u003c/td\u003e\n\u003c/ng-template\u003e\n```\n\n`\u003ccerious-scroll\u003e` exposes the same via `[headerTemplate]` and `\u003cng-template ceriousScrollItem\u003e`.\n\n- The **header template** renders into the engine's `\u003cthead\u003e` (same `\u003ctable\u003e` as the rows → native column alignment, frozen header).\n- The **row template's root nodes must be `\u003ctd\u003e`s** (don't wrap them in a structural directive at the root — that hides the cells from the directive's recycle re-append).\n- **`table.autoSizeColumns`** measures column widths once and pins them (auto-sized + stable); or use `table.columnWidths`. Variable row heights work as usual.\n- CSS: `border-collapse: separate` and an **opaque `\u003cthead\u003e` background** (see the core README's [Table Layout](https://github.com/ceriousdevtech/cerious-scroll#-table-layout-layout-table) notes).\n\n---\n\n## Notes\n\n- **No height estimation.** Rows are committed synchronously via\n  `EmbeddedViewRef.detectChanges()` so the engine measures real `offsetHeight`.\n  Later size changes are picked up by the engine's built-in `ResizeObserver`.\n- **`options` are read at creation.** Changing `options` after init has no\n  effect; recreate the host (e.g. with `*ngIf` toggling) to apply new engine\n  options.\n- **Changing the item count** recreates the engine internally (scroll position\n  is preserved). Mutating items without changing the count just re-renders the\n  content in place (cheap; Angular patches each row, so focus/selection survive)\n  — it does **not** discard cached heights, so editable grids that produce a new\n  `items` array on every edit don't trigger a full viewport re-measure.\n- **If every rendered row's height changes at once** (e.g. a density/layout\n  switch) the cached heights become stale and rows can misalign until the next\n  scroll. Call `recalculate()` on the directive instance right after the change\n  to drop the height cache and re-measure. Don't call it on routine edits — a\n  single cell edit keeps its row's size, and the engine's built-in\n  `ResizeObserver` picks up any incidental resize on its own.\n\n---\n\n## License\n\nLicensed by **Cerious DevTech LLC** under the **MIT License** (see `LICENSE`).\n\n📧 info@ceriousdevtech.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceriousdevtech%2Fngx-cerious-scroll","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fceriousdevtech%2Fngx-cerious-scroll","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceriousdevtech%2Fngx-cerious-scroll/lists"}