Skip to content

Extras

Virtualize

Bit.BlazorUI.ExtrasVirtualScrollWindowing

BitVirtualize renders only the items in its scroll viewport, plus a small overscan buffer, so lists of millions of items scroll as smoothly as a few dozen. Items can share one size or be measured as they render, come from memory or be loaded window by window, scroll vertically or horizontally (by themselves, or with an ancestor or the page) and be laid out in a fixed or responsive grid of lanes. It adds header and footer content, sticky group headers, infinite scrolling in both directions, a bottom-anchored chat mode, programmatic scrolling and full keyboard and screen-reader support.

Notes

To use this component, you need to install the Bit.BlazorUI.Extras(opens in a new tab) nuget package, as described in the Optional steps of the Getting started page.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

An in-memory Items collection with a fixed ItemSize (px along the scroll axis). Only the rows in view, plus OverscanCount rows on each side (3 by default), are in the DOM. The list is its own scroll container, so give it a height.

ItemsProvider

An ItemsProvider loads the data window by window: it gets the StartIndex and Count needed and returns them with the TotalItemCount. Obsolete requests are cancelled and loaded items cached. LoadingTemplate shows until the first window arrives, PlaceholderTemplate fills each slot still loading. With several templates, the item one is ItemTemplate.

Loading

Dynamic size

With Dynamic, every rendered item is measured and its size remembered; the rest are assumed to be EstimatedItemSize px. When an item above the viewport turns out a different size, the scroll is corrected so the content in view never jumps.

Horizontal

Horizontal scrolls along the x-axis; ItemSize becomes the width of each item.

Grid (Lanes)

Lanes lays the items side by side in equal columns (rows when Horizontal), turning the list into a virtualized grid; ItemSize is then the height of a row. MinLaneSize makes it responsive: as many lanes as fit at that minimum width (resize the window). Gap spaces the rows and the lanes. The arrow keys move across and along the lanes, and in Dynamic mode each row is as tall as its tallest item.


Scrolling

InitialIndex opens the list at an item. ScrollToIndexAsync brings an item into view aligned to its Start, Center or End, or by the least movement (Auto); ScrollToOffsetAsync, ScrollByAsync, ScrollToStartAsync and ScrollToEndAsync cover the rest. Each can animate, and a call made before the list is ready is applied once it is. OnVisibleRangeChanged reports the visible [Start, End), and OnAtStartChanged / OnAtEndChanged whether an edge is reached.


[0, 20) visible

ScrollerSelector

By default the list scrolls itself. ScrollerSelector hands the scrolling to an ancestor (or to the page, with "window"): the list grows to the full size of its items, scrolls along with the content around it, and still renders only the items in view.

Content above the list scrolls away with it.
Content below the list.

Keyboard & accessibility

Each item carries its position in the whole list (aria-posinset / aria-setsize), so a screen reader says "article 12 of 10,000" with only a few items in the DOM. Here Role and ItemRole (list / listitem by default) make a feed of articles, AriaLabel names it and ItemAttributes labels each focusable article. Tab in, then use the arrows, PageUp / PageDown, Home and End: only the focused item is tabbable, and it stays focused when scrolled away. Keys pressed in an item's own controls are left to them.

Templates

HeaderTemplate and FooterTemplate scroll with the items, inside the list. EmptyTemplate replaces the items when there are none. IndexedItemTemplate also receives each item's Index in the whole list, here to number and stripe the rows.


Header · 1,000 items

Infinite scrolling

OnEndReached fires once per item count when the last item comes within ReachedThreshold items of the view. The handler appends a batch and calls RefreshDataAsync (or passes a new collection).

Sticky headers

IsStickyItem marks the group headers: the current one stays pinned while its group scrolls, and the next pushes it out. StickyTemplate renders the pinned copy, which is hidden from assistive technologies (they read the real header in its place).

ItemKey

By default rows are keyed by index, so an insertion hands every following row's state to another item. With ItemKey each row keeps its state (tick some boxes, then add or remove tasks), measured sizes follow their items, and the item at the top stays put when items change above it (scroll down a little first).


Reversed (chat)

Reversed starts at the newest message and stays pinned there as messages arrive. Scrolling up, OnStartReached prepends older history without moving the view, and OnAtEndChanged highlights "Jump to latest" while the newest messages are out of view. AlignToEnd keeps a short conversation at the bottom (start a new one to see it).

Scroll up for older messages

Cascading parameters

BitParams with a BitVirtualizeParams sets defaults (sizing, overscan, roles, state templates, styles) for every list under it. A list's own value wins: the second keeps its own ItemSize.


Style & Class

Style and Class reach the root, which is the scroll container. Styles and Classes reach each part: Root, Header, Item, Sticky, Footer, Loading and Empty. The public --bit-Virtualize-* CSS variables restyle the focus ring, the pinned item and the states, here or for the whole app from :root.

Style & Class:



Styles:

Header


Classes:



CSS variables (Tab in to see the focus ring):

RTL

With Dir set to Rtl, a horizontal list starts at the right and scrolls left, and the arrow keys follow the reading direction (ArrowLeft moves to the next item, or the next lane of a grid).

CSS variables

The public custom properties this component reads off its root, for what no parameter covers.

Every variable is read with a fallback and never declared by the component, so it inherits like any other custom property: set one on :root (or in a [bit-theme] block) to restyle every instance, on any ancestor to restyle the ones inside it, or on the Style of one instance to restyle it - and any instance nested inside it, which inherits the value too; a parameter changes one alone, as does the real CSS property on the instance's Style / Styles when that property does not inherit (opacity: 1 keeps one disabled instance undimmed without undimming a disabled one inside it), while an inherited one such as color or font-family also reaches the nested instances that do not set it themselves. Leave a variable unset and the component falls back to the theme token beside it.

BitVirtualize CSS variables

Name Default value Description
--bit-Virtualize-focus-color var(--bit-clr-pri-focus) Focus indicator of the list and of its items.
--bit-Virtualize-sticky-background var(--bit-clr-bg-pri) Background of the pinned sticky item, which hides the items scrolling under it.
--bit-Virtualize-sticky-shadow none Shadow under the pinned sticky item.
--bit-Virtualize-state-color var(--bit-clr-fg-sec) Text color of the loading and empty content.
--bit-Virtualize-state-font-size var(--bit-tpg-fs-sm) Font size of the loading and empty content.
--bit-Virtualize-state-padding spacing(2) Padding of the loading and empty content.

API

Every parameter, public member, sub-class and enum this component exposes.

BitVirtualize parameters

Name Type Default value Description
AlignToEnd bool false Pushes the items to the end (bottom, or the right in horizontal mode) of the viewport while they are too few to fill it, the way a chat conversation starts at the bottom. Pairs naturally with Reversed.
ChildContent RenderFragment<TItem>? null The custom template to render each item.
Classes BitVirtualizeClassStyles? null Custom CSS classes for different parts of the BitVirtualize.
Dynamic bool false Enables dynamic item sizing in which each rendered item gets measured in the browser and its real size gets cached, using the EstimatedItemSize for the items that have not been measured yet.
EmptyTemplate RenderFragment? null The custom template to render when there is no item available.
EstimatedItemSize float 50 The assumed size in pixels of the items that have not been measured yet in dynamic mode.
Gap float 0 The space in pixels between consecutive items along the scroll axis, and between the lanes of a grid.
FooterTemplate RenderFragment? null The custom template to render after the last item, inside the scroll container (for example, a loading indicator at the end of an infinite list).
HeaderTemplate RenderFragment? null The custom template to render before the first item, inside the scroll container.
Horizontal bool false Renders the items horizontally so the viewport scrolls along the x-axis.
IndexedItemTemplate RenderFragment<BitVirtualizeItemContext<TItem>>? null The custom template to render each item, which also receives the index of the item in the whole list (for example, for numbering or striping the rows). Takes precedence over ItemTemplate and ChildContent.
InitialIndex int? null The index of the item to scroll to on the first render. Ignored when Reversed is set.
IsStickyItem Func<TItem, bool>? null A predicate that marks certain items (for example, group headers) as sticky. The active sticky item gets pinned to the leading edge of the viewport while its group scrolls. Fully supported with in-memory Items; in provider mode it is applied on a best-effort basis to the currently loaded window. A change in the state the predicate reads, rather than in the predicate itself, gets applied by RefreshDataAsync.
Items ICollection<TItem>? null The in-memory collection of items to virtualize. Mutually exclusive with ItemsProvider.
ItemAttributes Func<TItem, IReadOnlyDictionary<string, object>?>? null A function that returns extra HTML attributes for the element of an item, which is the one that takes the keyboard focus: an aria-selected, aria-labelledby or aria-describedby for assistive technologies, a class or a style for the whole slot of the item. A role or an aria attribute it returns overrides the default one, while a class or a style is appended to the ones of the component.
ItemKey Func<TItem, object>? null A function that returns a stable and unique identity key for an item. When provided, rendered rows are keyed by identity (instead of by index) so per-item DOM/component state survives insertions, removals and reordering, dynamic measurements follow their item across those mutations, and the item in view stays in place when items get inserted or removed before it.
ItemRole string? listitem The ARIA role of each item element.
ItemSize float 50 The size in pixels of each item (each row of items with Lanes) along the scroll axis when the Dynamic mode is off.
ItemsProvider BitVirtualizeItemsProvider<TItem>? null The item provider function that lazily supplies windows of items on demand. Mutually exclusive with Items.
ItemTemplate RenderFragment<TItem>? null Alias for ChildContent.
Lanes int 1 The number of items laid side by side across the scroll axis, which turns the list into a virtualized grid: the items fill each row (each column in horizontal mode) from the start, every one as wide as an equal share of the row, and the arrow keys move across the lanes as well as along them. In dynamic mode a row is as tall as its tallest item.
LoadingTemplate RenderFragment? null The custom template to render until the component has performed its first load.
MinLaneSize float? null The smallest size in pixels of a lane across the scroll axis, which makes the grid responsive: the list has as many lanes as fit in its width (its height in horizontal mode), at least one. Takes precedence over Lanes once the list has been measured.
OnAtEndChanged EventCallback<bool> The callback to be called when the viewport arrives at the end of the list (true) or leaves it (false), for example to show a "Jump to latest" button only while the newest items are out of view. Also called with the initial state once the list has taken its initial position. The end is the one ScrollToEndAsync goes to, the FooterTemplate included; an emptied list is at both edges.
OnAtStartChanged EventCallback<bool> The callback to be called when the viewport arrives at the start of the list (true) or leaves it (false), for example to show a "Back to top" button only once the user has scrolled away. Also called with the initial state once the list has taken its initial position. The start is the one ScrollToStartAsync goes to, the HeaderTemplate included; an emptied list is at both edges.
OnEndReached EventCallback The callback to be called when the last item comes within ReachedThreshold items of the visible window, useful for appending more data in infinite scrolling scenarios. Fires once per item-count value.
OnStartReached EventCallback The callback to be called when the first item comes within ReachedThreshold items of the visible window, useful for prepending older data (for example, loading chat history when scrolling up). Fires again when items get prepended while the start is still within reach.
OnVisibleRangeChanged EventCallback<(int Start, int End)> The callback to be called whenever the visible index range changes.
OverscanCount int 3 The number of extra items to render on each side of the visible window for smoother scrolling.
PlaceholderTemplate RenderFragment<BitVirtualizePlaceholderContext>? null The custom template to render an item whose data has not been loaded yet in provider mode, the first window too: before the provider tells the count of the items (and so in a prerendered or statically rendered page) the window it is first asked for is rendered as placeholders, unless a LoadingTemplate is provided.
ReachedThreshold int 0 The number of items away from an edge the visible window must be before OnEndReached/OnStartReached fire.
Reversed bool false Enables the bottom-anchored mode in which the list starts scrolled to the end and automatically keeps the newest items in view when data gets appended while the user is at the bottom. Ideal for chat and log views.
Role string? list The ARIA role of the root element, which is a group instead while the loading or the empty content takes the place of the items.
ScrollerSelector string? null The CSS selector of an ancestor that scrolls the list instead of the list itself, which then grows to the full size of its items and only virtualizes them; the "window", "document", "body" and "html" values select the page itself. The list then has no height of its own to give.
StickyTemplate RenderFragment<TItem>? null The custom template to render the pinned sticky item. Falls back to the item template when not provided.
Styles BitVirtualizeClassStyles? null Custom CSS styles for different parts of the BitVirtualize.

BitVirtualize public members

Name Type Default value Description
RefreshDataAsync Func<Task> Re-requests the data from the ItemsProvider (or re-reads the Items) and refreshes the view.
ScrollToIndexAsync Func<int, BitScrollAlignment, bool, Task> Scrolls the viewport so that the item at the provided index becomes visible. A call made before the component is ready (for example, before its data arrives) gets applied once it is.
ScrollToOffsetAsync Func<double, bool, Task> Scrolls to an absolute pixel offset along the scroll axis, measured from the start of the first item.
ScrollByAsync Func<double, bool, Task> Scrolls the viewport by the provided number of pixels along the scroll axis (negative values scroll back).
ScrollToStartAsync Func<bool, Task> Scrolls to the very start (top/left) of the list, including the HeaderTemplate.
ScrollToEndAsync Func<bool, Task> Scrolls to the very end (bottom/right) of the list, including the FooterTemplate. Useful for chat and log views.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
Disabled bool false Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name.
Id string? null Gets or sets the unique identifier for the component's root element.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitVirtualizeItemsProviderRequest properties

The request passed to the ItemsProvider function for a window of items.

Name Type Default value Description
StartIndex int 0 The zero-based index of the first item requested.
Count int 0 The maximum number of items requested.
CancellationToken CancellationToken A token that is cancelled when this request is no longer needed.

BitVirtualizeItemsProviderResult<TItem> properties

The result returned from the ItemsProvider function.

Name Type Default value Description
Items IReadOnlyList<TItem> The items that were loaded for the requested window.
TotalItemCount int 0 The total number of items in the underlying data source.

BitVirtualizeItemContext<TItem> properties

The context passed to the IndexedItemTemplate: an item along with its position in the whole list.

Name Type Default value Description
Item TItem The item to render.
Index int 0 The zero-based index of the item in the whole list (not in the rendered window).

BitVirtualizePlaceholderContext properties

The context passed to the PlaceholderTemplate while real items are being loaded.

Name Type Default value Description
Index int 0 The zero-based index of the item this placeholder represents.
Size double 0 The estimated size (px) reserved for the placeholder along the scroll axis.

BitVirtualizeClassStyles properties

Custom CSS classes/styles for the different parts of the BitVirtualize.

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root (scroll container) element of the BitVirtualize.
Header string? null Custom CSS classes/styles for the header container of the BitVirtualize.
Item string? null Custom CSS classes/styles for the wrapper element of each rendered item (and placeholder) of the BitVirtualize.
Sticky string? null Custom CSS classes/styles for the pinned sticky item container of the BitVirtualize.
Footer string? null Custom CSS classes/styles for the footer container of the BitVirtualize.
Loading string? null Custom CSS classes/styles for the loading container of the BitVirtualize.
Empty string? null Custom CSS classes/styles for the empty container of the BitVirtualize.

BitScrollAlignment enum

Name Value Description
Start 0 The element is brought to the start of the pane: its top edge to the top of the pane, and its leading edge to the leading edge of the pane.
Center 1 The element is centered in the pane along both axes.
End 2 The element is brought to the end of the pane: its bottom edge to the bottom of the pane, and its trailing edge to the trailing edge of the pane.
Nearest 3 The pane moves as little as it can: an element that is already fully in view is not moved to at all, and one that is not is brought to whichever edge it is nearest.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.