ASP.NET Core Blazor component virtualization

By Daniel Roth

Improve the perceived performance of component rendering using the Blazor framework's built-in virtualization support. Virtualization is a technique for limiting UI rendering to just the parts that are currently visible. For example, virtualization is helpful when the app must render a long list of items and only a subset of items is required to be visible at any given time. Blazor provides the Virtualize component that can be used to add virtualization to an app's components.

Without virtualization, a typical list might use a C# foreach loop to render each item in the list:

@foreach (var employee in employees)
{
    <p>
        @employee.FirstName @employee.LastName has the 
        job title of @employee.JobTitle.
    </p>
}

If the list contains thousands of items, then rendering the list may take a long time. The user may experience a noticeable UI lag.

Instead of rendering each item in the list all at one time, replace the foreach loop with the Virtualize component and specify a fixed item source with Items. Only the items that are currently visible are rendered:

<Virtualize Context="employee" Items="@employees">
    <p>
        @employee.FirstName @employee.LastName has the 
        job title of @employee.JobTitle.
    </p>
</Virtualize>

If not specifying a context to the component with Context, use the context value (@context.{PROPERTY}) in the item content template:

<Virtualize Items="@employees">
    <p>
        @context.FirstName @context.LastName has the 
        job title of @context.JobTitle.
    </p>
</Virtualize>

The Virtualize component calculates how many items to render based on the height of the container and the size of the rendered items.

The item content for the Virtualize component can include:

  • Plain HTML and Razor code, as the preceding example shows.
  • One or more Razor components.
  • A mix of HTML/Razor and Razor components.

Item provider delegate

If you don't want to load all of the items into memory, you can specify an items provider delegate method to the component's ItemsProvider parameter that asynchronously retrieves the requested items on demand:

<Virtualize Context="employee" ItemsProvider="@LoadEmployees">
    <p>
        @employee.FirstName @employee.LastName has the 
        job title of @employee.JobTitle.
    </p>
</Virtualize>

The items provider receives an ItemsProviderRequest, which specifies the required number of items starting at a specific start index. The items provider then retrieves the requested items from a database or other service and returns them as an ItemsProviderResult<TItem> along with a count of the total items. The items provider can choose to retrieve the items with each request or cache them so that they're readily available. Don't attempt to use an items provider and assign a collection to Items for the same Virtualize component.

The following example loads employees from an EmployeeService:

private async ValueTask<ItemsProviderResult<Employee>> LoadEmployees(
    ItemsProviderRequest request)
{
    var numEmployees = Math.Min(request.Count, totalEmployees - request.StartIndex);
    var employees = await EmployeesService.GetEmployeesAsync(request.StartIndex, 
        numEmployees, request.CancellationToken);

    return new ItemsProviderResult<Employee>(employees, totalEmployees);
}

Placeholder

Because requesting items from a remote data source might take some time, you have the option to render a placeholder (<Placeholder>...</Placeholder>) until the item data is available:

<Virtualize Context="employee" ItemsProvider="@LoadEmployees">
    <ItemContent>
        <p>
            @employee.FirstName @employee.LastName has the 
            job title of @employee.JobTitle.
        </p>
    </ItemContent>
    <Placeholder>
        <p>
            Loading&hellip;
        </p>
    </Placeholder>
</Virtualize>

Item size

The size of each item in pixels can be set with ItemSize (default: 50px):

<Virtualize Context="employee" Items="@employees" ItemSize="25">
    ...
</Virtualize>

Overscan count

OverscanCount determines how many additional items are rendered before and after the visible region. This setting helps to reduce the frequency of rendering during scrolling. However, higher values result in more elements rendered in the page (default: 3):

<Virtualize Context="employee" Items="@employees" OverscanCount="4">
    ...
</Virtualize>

State changes

When making changes to items rendered by the Virtualize component, call StateHasChanged to force re-evaluation and rerendering of the component.