igniteui-angular 22.1.4 → 22.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +2 -2
  2. package/combo/README.md +19 -0
  3. package/drop-down/README.md +40 -4
  4. package/fesm2022/igniteui-angular-accordion.mjs +7 -7
  5. package/fesm2022/igniteui-angular-action-strip.mjs +10 -10
  6. package/fesm2022/igniteui-angular-avatar.mjs +7 -7
  7. package/fesm2022/igniteui-angular-badge.mjs +7 -7
  8. package/fesm2022/igniteui-angular-banner.mjs +10 -10
  9. package/fesm2022/igniteui-angular-bottom-nav.mjs +22 -22
  10. package/fesm2022/igniteui-angular-button-group.mjs +12 -13
  11. package/fesm2022/igniteui-angular-button-group.mjs.map +1 -1
  12. package/fesm2022/igniteui-angular-calendar.mjs +61 -61
  13. package/fesm2022/igniteui-angular-card.mjs +31 -31
  14. package/fesm2022/igniteui-angular-carousel.mjs +22 -22
  15. package/fesm2022/igniteui-angular-chat-extras.mjs +6 -6
  16. package/fesm2022/igniteui-angular-chat.mjs +12 -12
  17. package/fesm2022/igniteui-angular-checkbox.mjs +7 -7
  18. package/fesm2022/igniteui-angular-chips.mjs +10 -10
  19. package/fesm2022/igniteui-angular-combo.mjs +268 -124
  20. package/fesm2022/igniteui-angular-combo.mjs.map +1 -1
  21. package/fesm2022/igniteui-angular-core.mjs +207 -59
  22. package/fesm2022/igniteui-angular-core.mjs.map +1 -1
  23. package/fesm2022/igniteui-angular-date-picker.mjs +80 -106
  24. package/fesm2022/igniteui-angular-date-picker.mjs.map +1 -1
  25. package/fesm2022/igniteui-angular-dialog.mjs +13 -13
  26. package/fesm2022/igniteui-angular-directives.mjs +321 -457
  27. package/fesm2022/igniteui-angular-directives.mjs.map +1 -1
  28. package/fesm2022/igniteui-angular-drop-down.mjs +331 -104
  29. package/fesm2022/igniteui-angular-drop-down.mjs.map +1 -1
  30. package/fesm2022/igniteui-angular-expansion-panel.mjs +28 -28
  31. package/fesm2022/igniteui-angular-grids-core.mjs +552 -516
  32. package/fesm2022/igniteui-angular-grids-core.mjs.map +1 -1
  33. package/fesm2022/igniteui-angular-grids-grid.mjs +79 -80
  34. package/fesm2022/igniteui-angular-grids-grid.mjs.map +1 -1
  35. package/fesm2022/igniteui-angular-grids-hierarchical-grid.mjs +59 -46
  36. package/fesm2022/igniteui-angular-grids-hierarchical-grid.mjs.map +1 -1
  37. package/fesm2022/igniteui-angular-grids-lite.mjs +12 -12
  38. package/fesm2022/igniteui-angular-grids-pivot-grid.mjs +113 -86
  39. package/fesm2022/igniteui-angular-grids-pivot-grid.mjs.map +1 -1
  40. package/fesm2022/igniteui-angular-grids-tree-grid.mjs +57 -57
  41. package/fesm2022/igniteui-angular-grids-tree-grid.mjs.map +1 -1
  42. package/fesm2022/igniteui-angular-icon.mjs +10 -10
  43. package/fesm2022/igniteui-angular-input-group.mjs +73 -83
  44. package/fesm2022/igniteui-angular-input-group.mjs.map +1 -1
  45. package/fesm2022/igniteui-angular-list.mjs +40 -40
  46. package/fesm2022/igniteui-angular-navbar.mjs +13 -13
  47. package/fesm2022/igniteui-angular-navigation-drawer.mjs +16 -16
  48. package/fesm2022/igniteui-angular-paginator.mjs +19 -19
  49. package/fesm2022/igniteui-angular-progressbar.mjs +19 -19
  50. package/fesm2022/igniteui-angular-query-builder.mjs +23 -23
  51. package/fesm2022/igniteui-angular-query-builder.mjs.map +1 -1
  52. package/fesm2022/igniteui-angular-radio.mjs +59 -35
  53. package/fesm2022/igniteui-angular-radio.mjs.map +1 -1
  54. package/fesm2022/igniteui-angular-select.mjs +36 -48
  55. package/fesm2022/igniteui-angular-select.mjs.map +1 -1
  56. package/fesm2022/igniteui-angular-simple-combo.mjs +44 -33
  57. package/fesm2022/igniteui-angular-simple-combo.mjs.map +1 -1
  58. package/fesm2022/igniteui-angular-slider.mjs +28 -28
  59. package/fesm2022/igniteui-angular-snackbar.mjs +7 -7
  60. package/fesm2022/igniteui-angular-splitter.mjs +13 -13
  61. package/fesm2022/igniteui-angular-stepper.mjs +34 -34
  62. package/fesm2022/igniteui-angular-switch.mjs +7 -7
  63. package/fesm2022/igniteui-angular-tabs.mjs +34 -34
  64. package/fesm2022/igniteui-angular-time-picker.mjs +32 -51
  65. package/fesm2022/igniteui-angular-time-picker.mjs.map +1 -1
  66. package/fesm2022/igniteui-angular-toast.mjs +7 -7
  67. package/fesm2022/igniteui-angular-tree.mjs +28 -28
  68. package/fesm2022/igniteui-angular-virtual-scroll.mjs +1257 -0
  69. package/fesm2022/igniteui-angular-virtual-scroll.mjs.map +1 -0
  70. package/fesm2022/igniteui-angular.mjs +1 -0
  71. package/fesm2022/igniteui-angular.mjs.map +1 -1
  72. package/input-group/README.md +2 -0
  73. package/lib/core/styles/components/scrollbar/scrollbar-component.scss +0 -2
  74. package/lib/core/styles/components/scrollbar/scrollbar-theme.scss +23 -51
  75. package/lib/grids/core/src/column-actions/themes/_derived.scss +3 -3
  76. package/lib/grids/core/src/filtering/excel-style/themes/_derived.scss +3 -3
  77. package/lib/grids/themes/_derived.scss +3 -3
  78. package/lib/query-builder/src/query-builder/themes/_derived.scss +3 -3
  79. package/migrations/common/UpdateChanges.d.ts +36 -0
  80. package/migrations/common/UpdateChanges.js +175 -31
  81. package/migrations/common/UpdateChanges.spec.js +66 -0
  82. package/migrations/migration-collection.json +10 -0
  83. package/migrations/update-22_2_0/changes/theme-changes.json +77 -0
  84. package/migrations/update-22_2_0/index.d.ts +3 -0
  85. package/migrations/update-22_2_0/index.js +18 -0
  86. package/migrations/update-22_2_0/index.spec.d.ts +1 -0
  87. package/migrations/update-22_2_0/index.spec.js +161 -0
  88. package/migrations/update-22_2_0_grid-summary-borders/changes/theme-changes.json +17 -0
  89. package/migrations/update-22_2_0_grid-summary-borders/index.d.ts +3 -0
  90. package/migrations/update-22_2_0_grid-summary-borders/index.js +64 -0
  91. package/migrations/update-22_2_0_grid-summary-borders/index.spec.d.ts +1 -0
  92. package/migrations/update-22_2_0_grid-summary-borders/index.spec.js +100 -0
  93. package/package.json +6 -2
  94. package/schematics/tsconfig.tsbuildinfo +1 -1
  95. package/simple-combo/README.md +3 -0
  96. package/skills/igniteui-angular-components/references/form-controls.md +58 -0
  97. package/styles/igniteui-angular-dark.css +1 -1
  98. package/styles/igniteui-angular.css +1 -1
  99. package/styles/igniteui-bootstrap-dark.css +1 -1
  100. package/styles/igniteui-bootstrap-light.css +1 -1
  101. package/styles/igniteui-dark-green.css +1 -1
  102. package/styles/igniteui-fluent-dark-excel.css +1 -1
  103. package/styles/igniteui-fluent-dark-word.css +1 -1
  104. package/styles/igniteui-fluent-dark.css +1 -1
  105. package/styles/igniteui-fluent-light-excel.css +1 -1
  106. package/styles/igniteui-fluent-light-word.css +1 -1
  107. package/styles/igniteui-fluent-light.css +1 -1
  108. package/styles/igniteui-indigo-dark.css +1 -1
  109. package/styles/igniteui-indigo-light.css +1 -1
  110. package/styles/maps/igniteui-angular-dark.css.map +1 -1
  111. package/styles/maps/igniteui-angular.css.map +1 -1
  112. package/styles/maps/igniteui-bootstrap-dark.css.map +1 -1
  113. package/styles/maps/igniteui-bootstrap-light.css.map +1 -1
  114. package/styles/maps/igniteui-dark-green.css.map +1 -1
  115. package/styles/maps/igniteui-fluent-dark-excel.css.map +1 -1
  116. package/styles/maps/igniteui-fluent-dark-word.css.map +1 -1
  117. package/styles/maps/igniteui-fluent-dark.css.map +1 -1
  118. package/styles/maps/igniteui-fluent-light-excel.css.map +1 -1
  119. package/styles/maps/igniteui-fluent-light-word.css.map +1 -1
  120. package/styles/maps/igniteui-fluent-light.css.map +1 -1
  121. package/styles/maps/igniteui-indigo-dark.css.map +1 -1
  122. package/styles/maps/igniteui-indigo-light.css.map +1 -1
  123. package/types/igniteui-angular-calendar.d.ts +1 -1
  124. package/types/igniteui-angular-combo.d.ts +55 -12
  125. package/types/igniteui-angular-core.d.ts +73 -11
  126. package/types/igniteui-angular-date-picker.d.ts +3 -4
  127. package/types/igniteui-angular-directives.d.ts +50 -164
  128. package/types/igniteui-angular-drop-down.d.ts +76 -4
  129. package/types/igniteui-angular-grids-core.d.ts +63 -28
  130. package/types/igniteui-angular-grids-grid.d.ts +2 -7
  131. package/types/igniteui-angular-grids-hierarchical-grid.d.ts +5 -4
  132. package/types/igniteui-angular-grids-pivot-grid.d.ts +11 -5
  133. package/types/igniteui-angular-grids-tree-grid.d.ts +1 -1
  134. package/types/igniteui-angular-icon.d.ts +1 -1
  135. package/types/igniteui-angular-input-group.d.ts +18 -5
  136. package/types/igniteui-angular-query-builder.d.ts +1 -1
  137. package/types/igniteui-angular-radio.d.ts +16 -1
  138. package/types/igniteui-angular-select.d.ts +1 -2
  139. package/types/igniteui-angular-simple-combo.d.ts +7 -0
  140. package/types/igniteui-angular-stepper.d.ts +1 -1
  141. package/types/igniteui-angular-time-picker.d.ts +1 -3
  142. package/types/igniteui-angular-tree.d.ts +3 -3
  143. package/types/igniteui-angular-virtual-scroll.d.ts +408 -0
  144. package/types/igniteui-angular.d.ts +1 -0
  145. package/virtual-scroll/README.md +332 -0
@@ -0,0 +1,332 @@
1
+ # IgxVirtualScrollComponent
2
+
3
+ A high-performance virtual-scrolling component that renders only the items visible inside the viewport (plus a configurable over-scan buffer). It supports both vertical and horizontal axes, variable item sizes measured at runtime, lists far larger than the browser's maximum scroll coordinate, and remote / infinite scrolling through the `dataRequest` event.
4
+
5
+ ## Imports
6
+
7
+ ```ts
8
+ import {
9
+ IgxVirtualScrollComponent,
10
+ IgxVirtualItemDirective,
11
+ } from 'igniteui-angular/virtual-scroll';
12
+ ```
13
+
14
+ ---
15
+
16
+ ## Basic usage
17
+
18
+ Define your list and provide a template using the `igxVirtualItem` directive:
19
+
20
+ ```html
21
+ <igx-virtual-scroll [data]="items" style="height: 400px;">
22
+ <ng-template igxVirtualItem let-item let-i="index">
23
+ <div class="list-row">{{ i }}: {{ item.name }}</div>
24
+ </ng-template>
25
+ </igx-virtual-scroll>
26
+ ```
27
+
28
+ ```ts
29
+ @Component({ /* ... */ })
30
+ export class MyComponent {
31
+ items = Array.from({ length: 10_000 }, (_, i) => ({ name: `Item ${i}` }));
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Inputs
38
+
39
+ | Input | Type | Default | Description |
40
+ |---|---|---|---|
41
+ | `data` | `T[]` | `[]` | The array of items to virtualize. Compared by reference. See [Updating `data`](#updating-data). |
42
+ | `dataWindow` | `VirtualDataWindow<T> \| null` | `null` | A loaded page of a larger collection. Takes the place of `data` while it is set. See [Paged data](#paged-data). |
43
+ | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Scroll axis. |
44
+ | `overScan` | `number` | `2` | Extra items to render beyond each edge of the viewport. Higher values reduce blank flashes during fast scrolling at the cost of slightly more DOM nodes. Normalized to a non-negative integer. |
45
+ | `estimatedItemSize` | `number` | `50` | Pixel size used for items before they are measured in the DOM. Set this close to the real average size for the best initial-render accuracy. A non-positive value falls back to `50`. |
46
+ | `itemTemplate` | `TemplateRef<IgxVsItemContext<T>> \| null` | `null` | Programmatic template that takes precedence over a content `ng-template[igxVirtualItem]`. |
47
+
48
+
49
+ ### Paged data
50
+
51
+ For data that arrives a page at a time, bind `dataWindow` instead of `data`:
52
+
53
+ ```ts
54
+ interface VirtualDataWindow<T> {
55
+ readonly items: readonly T[]; // The loaded page
56
+ readonly startIndex: number; // The index items[0] has in the whole collection
57
+ readonly totalCount: number; // How many items the whole collection has
58
+ }
59
+ ```
60
+
61
+ The list is as long as `totalCount`, so the scrollbar spans the whole collection while only
62
+ the page is in memory. An index in the list is an index in that collection: the item at
63
+ `index` is `items[index - startIndex]`, and `IgxVsItemContext.index` and `.count` are the
64
+ global index and the total. Indices the page does not cover render nothing, so no template
65
+ is instantiated for an item that has not arrived.
66
+
67
+ `stateChange` reports the range the viewport wants, which is what a consumer supplies the
68
+ next page from:
69
+
70
+ ```ts
71
+ load(state: VirtualScrollState) {
72
+ const startIndex = state.startIndex;
73
+ this.service.fetch(startIndex, state.endIndex - startIndex + 1)
74
+ .subscribe(page => this.window = { items: page.rows, startIndex, totalCount: page.total });
75
+ }
76
+ ```
77
+
78
+ Sizes are measured and kept per index, and the rows a new page renders are measured again in
79
+ the DOM, so moving the window costs the page rather than the collection. This assumes the
80
+ indexing stays stable while `totalCount` holds. A page with another `totalCount` is taken as a
81
+ different collection, a filtered one for instance, and every size is measured again. A sort that
82
+ keeps the count but puts different records at the same indices leaves the sizes measured for the
83
+ previous ones in place, for the indices that are not re-rendered.
84
+
85
+ `dataRequest` is not emitted in this mode — it asks for items to append, which a sized
86
+ collection does not need.
87
+
88
+ Paging keeps the *items* down to a page, not the size bookkeeping. The engine holds one size
89
+ entry per index, so its memory grows with `totalCount` rather than with the page: roughly
90
+ 17 MB per million items. Give `totalCount` the size of the collection the consumer really
91
+ pages through; a value far beyond what the platform can allocate fails at the allocation.
92
+
93
+ ### Lists inside a popup
94
+
95
+ A list inside a drop-down, dialog or any other container that is hidden until it opens has
96
+ no size to measure in the change detection pass that reveals it. The component learns its
97
+ size from a `ResizeObserver` and from `afterNextRender`, both of which run after a render,
98
+ so that first render is laid out against a viewport of zero and produces no rows. The rows
99
+ arrive in the next frame, once the host has been measured.
100
+
101
+ A wrapper that reacts to whether the list has children can flip state between those passes,
102
+ which Angular reports as `NG0100` in development mode. Read the rows after `layoutComplete`
103
+ instead.
104
+
105
+ A host with no box at all — hidden or detached — is not measured, because the zero it reports
106
+ says nothing about how large it will be once shown. Its last measurement is kept so the list
107
+ renders its window in the pass that reveals it again. The deliberate consequence is that the
108
+ rendered window stays in the DOM while the host is away.
109
+
110
+ Changing `estimatedItemSize` re-applies it to every item that has **not** yet been measured in the DOM. Items that have been measured keep their real size.
111
+
112
+ ---
113
+
114
+ ## Outputs
115
+
116
+ | Output | Payload | Description |
117
+ |---|---|---|
118
+ | `stateChange` | `VirtualScrollState` | Emitted when the virtual window changes. It reports the range the viewport wants, over-scan included; with `dataWindow` bound that range can reach past the loaded page, so it is not always the set of rows in the DOM. Consecutive renders that produce an identical window are not re-emitted. |
119
+ | `dataRequest` | `VirtualScrollDataRequest` | Emitted when the rendered window comes within a few items of the end of `data`. Use this to implement infinite / remote scrolling. |
120
+
121
+ ---
122
+
123
+ ## Public API
124
+
125
+ ### `scrollToIndex(index: number, options?: ScrollIntoViewOptions): Promise<void>`
126
+
127
+ Scrolls the viewport to the item at `index`.
128
+
129
+ Items outside the rendered window only have an *estimated* size, so the first jump can miss the target. The component measures the items at the landing point and corrects the scroll position, repeating until the offset is stable. The returned promise resolves on that final offset; callers that only need the first, approximate scroll can ignore it.
130
+
131
+ ```ts
132
+ @ViewChild(IgxVirtualScrollComponent) vs!: IgxVirtualScrollComponent<any>;
133
+
134
+ // Leading edge, instant (the default).
135
+ await this.vs.scrollToIndex(500);
136
+
137
+ // Centered, animated.
138
+ await this.vs.scrollToIndex(500, { block: 'center', behavior: 'smooth' });
139
+
140
+ // Only scroll if the item is not already fully visible.
141
+ await this.vs.scrollToIndex(500, { block: 'nearest' });
142
+ ```
143
+
144
+ | Option | Values | Notes |
145
+ |---|---|---|
146
+ | `block` | `'start'` \| `'center'` \| `'end'` \| `'nearest'` | Alignment on the vertical axis. Defaults to `'start'`. |
147
+ | `inline` | same as `block` | Alignment on the horizontal axis; falls back to `block`. |
148
+ | `behavior` | `'auto'` \| `'smooth'` | Defaults to `'auto'`. |
149
+
150
+ `'nearest'` leaves the scroll position untouched when the item is already fully in view, or when the item is larger than the viewport and currently covers it. Otherwise it brings the item to its nearer edge: the start for an item before the viewport, the end for one past it. This matches native `scrollIntoView({ block: 'nearest' })`.
151
+
152
+ Out-of-range indices are clamped to the data, and the resulting offset is clamped to the largest reachable scroll position.
153
+
154
+ ### `layoutComplete: Promise<void>`
155
+
156
+ Resolves once the virtual scroll has settled: the current render pass is complete, the item-size measurements it triggered are complete, and so are the renders those measurements scheduled.
157
+
158
+ Useful when you need to read the resulting DOM after a `data` change, a scroll, or a viewport resize:
159
+
160
+ ```ts
161
+ this.items = await this.service.fetch();
162
+ await this.vs.layoutComplete;
163
+ // The rendered window and the track size now reflect the new data.
164
+ ```
165
+
166
+ ---
167
+
168
+ ## `IgxVirtualItemDirective`
169
+
170
+ Marks an `ng-template` as the item template for the nearest `igx-virtual-scroll`. The template context is typed as `IgxVsItemContext<T>`.
171
+
172
+ ### Template context variables
173
+
174
+ | Variable | Type | Description |
175
+ |---|---|---|
176
+ | `$implicit` (or `let-item`) | `T` | The current item. |
177
+ | `index` | `number` | The item's index within the full data array. |
178
+ | `count` | `number` | Total number of items in `data`. |
179
+ | `first` | `boolean` | `true` when `index === 0`. |
180
+ | `last` | `boolean` | `true` when `index === count - 1`. |
181
+ | `even` | `boolean` | `true` when `index` is even. |
182
+ | `odd` | `boolean` | `true` when `index` is odd. |
183
+
184
+ ```html
185
+ <ng-template igxVirtualItem let-item let-i="index" let-first="first">
186
+ <div [class.first-row]="first">{{ i }}: {{ item }}</div>
187
+ </ng-template>
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Output type reference
193
+
194
+ ### `VirtualScrollState`
195
+
196
+ ```ts
197
+ interface VirtualScrollState {
198
+ startIndex: number; // First item index of the wanted range
199
+ endIndex: number; // Last item index of the wanted range (inclusive)
200
+ viewportSize: number; // Viewport height (or width) in px
201
+ totalSize: number; // Total virtual content size in px
202
+ }
203
+ ```
204
+
205
+ The range is what the viewport wants, the over-scan buffer included. Bound to `data` that is
206
+ the set of rows in the DOM. Bound to `dataWindow` it is the range to load next, and the rows
207
+ actually rendered are its intersection with the page - which can be narrower, or empty.
208
+
209
+ ### `VirtualScrollDataRequest`
210
+
211
+ ```ts
212
+ interface VirtualScrollDataRequest {
213
+ startIndex: number; // First index that does not yet have data
214
+ count: number; // Suggested number of items to fetch
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Updating `data`
221
+
222
+ `data` is compared **by reference**. Mutating the array in place (`items.push(...)`) does not trigger an update. Assign a new array instead.
223
+
224
+ The component diffs the new array against the previous one to decide which item measurements it can keep:
225
+
226
+ * **Appending** (`[...items, ...more]`) keeps the identity of every existing index, so all previous measurements are retained.
227
+ * **Replacing, filtering or sorting** invalidates every index from the first difference onwards; those items are measured again on their next render.
228
+
229
+ ---
230
+
231
+ ## Horizontal scrolling
232
+
233
+ Set `orientation="horizontal"`. Items are laid out in a row; ensure each item has an explicit `width` so the engine can measure sizes correctly.
234
+
235
+ ```html
236
+ <igx-virtual-scroll [data]="items" orientation="horizontal" style="width: 100%; height: 60px;">
237
+ <ng-template igxVirtualItem let-item>
238
+ <div class="col" style="width: 120px; height: 60px;">{{ item }}</div>
239
+ </ng-template>
240
+ </igx-virtual-scroll>
241
+ ```
242
+
243
+ Right-to-left (RTL) layouts are fully supported. When the component (or an ancestor) sets `dir="rtl"`, horizontal scrolling, content positioning, and `scrollToIndex` are mirrored automatically. No extra configuration is required.
244
+
245
+ ---
246
+
247
+ ## Infinite / remote scrolling
248
+
249
+ Listen to the `dataRequest` output and append more items to the `data` array:
250
+
251
+ ```html
252
+ <igx-virtual-scroll [data]="items" (dataRequest)="loadMore($event)" style="height: 500px;">
253
+ <ng-template igxVirtualItem let-item>
254
+ <div class="row">{{ item.label }}</div>
255
+ </ng-template>
256
+ </igx-virtual-scroll>
257
+ ```
258
+
259
+ ```ts
260
+ loadMore(req: VirtualScrollDataRequest) {
261
+ this.myService.fetch(req.startIndex, req.count).subscribe(newItems => {
262
+ this.items = [...this.items, ...newItems];
263
+ });
264
+ }
265
+ ```
266
+
267
+ `dataRequest` is also emitted on the **first render** when the initially loaded items do not fill the viewport, so a short initial `data` array is enough to start the loading chain. An **empty** array is not: with nothing loaded there is no rendered window to run out of, so load the first page yourself and let `dataRequest` carry the rest.
268
+
269
+ Only one request is in flight at a time: the next one is emitted after `data` changes. If your source is exhausted and you reassign `data` without adding items, the component will not ask again for the same `startIndex`.
270
+
271
+ ---
272
+
273
+ ## Programmatic template
274
+
275
+ Pass a `TemplateRef` via `[itemTemplate]` when the template is defined outside the component:
276
+
277
+ ```html
278
+ <ng-template #myTpl let-item>
279
+ <div>{{ item }}</div>
280
+ </ng-template>
281
+
282
+ <igx-virtual-scroll [data]="items" [itemTemplate]="myTpl" style="height: 400px;" />
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Styling and DOM structure
288
+
289
+ ```html
290
+ <igx-virtual-scroll class="igx-virtual-scroll" data-orientation="vertical" role="list">
291
+ <div class="igx-virtual-scroll__track" role="presentation"> <!-- full virtual extent -->
292
+ <div class="igx-virtual-scroll__content" role="presentation"><!-- translated into position -->
293
+ <div class="igx-virtual-item" role="presentation" data-index="12">
294
+ <!-- your item template -->
295
+ </div>
296
+ ...
297
+ </div>
298
+ </div>
299
+ </igx-virtual-scroll>
300
+ ```
301
+
302
+ | Class / attribute | Element | Notes |
303
+ |---|---|---|
304
+ | `igx-virtual-scroll` | Host | Always present. |
305
+ | `data-orientation` | Host | Reflects the `orientation` input: `"vertical"` or `"horizontal"`. |
306
+ | `igx-virtual-scroll__track` | Inner spacer div | Sized to the full virtual height/width. |
307
+ | `igx-virtual-scroll__content` | Rendered-items wrapper | Absolutely positioned; translated to the correct virtual offset. |
308
+ | `igx-virtual-item` | Per-item wrapper | One per rendered item; carries `data-index` and is the element the engine measures. |
309
+
310
+ The host element must have a **fixed height** (vertical) or **fixed width** (horizontal) and `overflow: auto` or `overflow: scroll`. The default styles already set this.
311
+
312
+ ### Item sizing
313
+
314
+ Items are measured by their **border box**, so margins are not included and accumulate as drift down the list. Use `padding` on the item, or a `gap` on a wrapper, instead of margins.
315
+
316
+ ### Accessibility
317
+
318
+ Only the current window is in the DOM, so assistive technology cannot infer an item's position from the markup. The host carries `role="list"`; if your template renders a role with set semantics (`listitem`, `option`, `row`, ...), map the context's `index` and `count` onto `aria-posinset` and `aria-setsize`:
319
+
320
+ ```html
321
+ <ng-template igxVirtualItem let-item let-i="index" let-count="count">
322
+ <div role="listitem" [attr.aria-posinset]="i + 1" [attr.aria-setsize]="count">
323
+ {{ item }}
324
+ </div>
325
+ </ng-template>
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Very large lists
331
+
332
+ Browsers cap how far an element can scroll. When the total item size exceeds that limit, the component compresses the virtual coordinate space into the range the browser can represent and scales scroll positions accordingly. Items still render at their real pixel size, so lists of millions of items scroll correctly with no configuration.