Skip to main content

LgListView

LgListView<TItem> displays a collection as a customizable list, typically rendered as cards. Use it when each item must display rich content where a tabular grid would be less readable: the component provides the same data pipeline as LgGridView (local or remote [Queryable] loading, sorting, filtering, pagination) with rendering entirely controlled by the application. Like the grid, the list is rendered in an LgFrame: its header (title, actions, collapse) has the same appearance as LgGridView.

<LgListView TItem="ProjectVm" Items="_projects" Title="#ProjectsTitle">
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
  • Namespace: Lagoon.UI.Components
  • Inherits from: LgAriaComponentBase → LgComponentBase
  • NuGet package: Lagoon.UI

Usage​

Demo​

Try this component in the Lagoon showcase (overview), then feature by feature:

Simple list with card template​

Provide Items and ItemTemplate to control the rendering of each item: the template receives a ListViewItemContext<TItem> whose Item property carries the element. Without ItemTemplate, the component displays a default card (see Default card). When the source contains zero items, a "no data" message is displayed (NoDataTitle / NoDataDescription); a loading error displays DataErrorTitle with a retry button. The list header is rendered only if it has content: a Title, sorting, filters, a Toolbar, or selection (SelectableRows); a list embedded in another block (column, tab, window) thus has no empty header.

ProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
AriaLabel="#ProjectsListAriaLabel">
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
<LgLabel Text="@project.Item.StatusLabel" CssClass="ml-2" />
</LgCard>
</ItemTemplate>
</LgListView>
ProjectsPage.razor.cs
public partial class ProjectsPage : LgPage
{
// Contains the displayed items: on the next page render, the list is reloaded when the
// reference or number of items has changed (or after an event from an ObservableCollection);
// for any other mutation, or outside a page render, call RefreshAsync().
private readonly List<ProjectVm> _projects = new()
{
new ProjectVm { Name = "Lagoon Portal", StatusLabel = "#ProjectStatusActive" },
new ProjectVm { Name = "Lagoon Mobile", StatusLabel = "#ProjectStatusPending" }
};

// Minimal card model: carries only the data required for the template.
private sealed class ProjectVm
{
public string Name { get; set; }

public string StatusLabel { get; set; }
}
}

Header: title, actions, and collapse​

The list is a frame (LgFrame): Title, IconName, TitleContent, and Kind dress up its header like that of an LgFrame, and Collapsable allows it to be collapsed with a click on the header (Collapsed bindable in two-way, DefaultCollapsed for the initial state). Do not place an LgListView in an LgFrame: you would get a frame in a frame.

The action bar of the header follows the grid order: first buttons from Toolbar, then built-in buttons — "Filters" and "Clear" (with Filters, see Declarative filters) and the sort menu (with SortOptions, see Declarative sorting). Its buttons have the size of toolbar buttons of frames (App.BehaviorConfiguration.FrameToolbarButtonSize). When the list is collapsed, built-in buttons and the "Select all" checkbox are hidden; those from Toolbar remain visible.

The header is rendered only if it has content: Title, IconName, TitleContent, a filter declared in Filters, a sort in SortOptions, a Toolbar, selection (SelectableRows), or Collapsable. Without any of these, the list displays without a header.

As in the LgGridView title, two counters from the last load are replaced in Title, including after translation of a #key title: {0} by the total number of items (with filters applied) and {1} by the number of items in the displayed page (all items without AllowPaging). An unknown counter displays ...: before the first load, and for {1} when the page is empty ({0} is then 0). During a reload, counters from the previous load remain displayed. To display counters elsewhere than in the title, bind ListViewDataCounter (see Pagination).

CollapsableProjectsPage.razor
<!-- ProjectsCountTitle (Dico.xml) : fr="Projets ({0})" en="Projects ({0})" -->
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsCountTitle"
IconName="@IconNames.All.ListUl"
Collapsable="true"
@bind-Collapsed="_collapsed">
<Toolbar>
<LgToolbarButton Text="#AddProject" IconName="@IconNames.All.Plus" OnClick="AddProjectAsync" />
</Toolbar>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
CollapsableProjectsPage.razor.cs
public partial class CollapsableProjectsPage : LgPage
{
private readonly List<ProjectVm> _projects = new();

// Collapsed state bound in two-way: the page can read or modify it (e.g., collapse the list after an action).
private bool _collapsed;

// Adds an item: the component detects the change in number, reloads the list, and updates the title.
private Task AddProjectAsync(ActionEventArgs args)
{
_projects.Add(new ProjectVm { Name = "Lagoon Back Office" });
return Task.CompletedTask;
}

private sealed class ProjectVm
{
public string Name { get; set; }
}
}

Default card (without ItemTemplate)​

Without ItemTemplate, each item is rendered in an LgCard built from optional parameters:

  • BodyContent (RenderFragment<TItem>): content of the card body (div.card-body); if absent, item.ToString() is displayed.
  • ColorSelector (Func<TItem, string>): CSS color of the stripe (LgCardStripe) of the item.
  • StripeCssClassSelector (Func<TItem, string>): CSS classes of the stripe, to color it with a theme class (bg-danger for example) rather than a color.
  • StripeIconSelector (Func<TItem, string>): name of the icon displayed in the stripe.
  • StripeContent (RenderFragment<TItem>): content rendered inside the color stripe (a counter for example). The stripe then takes the width of its content (at minimum that of the variant with icon).
  • CssClassSelector (Func<TItem, string>): CSS classes added to the item's card.

The stripe is rendered for an item as soon as ColorSelector, StripeCssClassSelector, or StripeIconSelector returns a value (neither null nor empty string), or when StripeContent is set: StripeContent thus gives a stripe to all items. Without color or class, the stripe keeps the theme color, like an LgCardStripe without Color. An item without any of these four parameters has no stripe: its body then starts more to the left than that of items that have one.

The card also receives the click, active item, link, tooltip, and confirmation from the list (see Clickable cards and active item).

ItemTemplate takes precedence: when it is set, the default card is not generated, but its elements remain available in the template (see Reusing the card in ItemTemplate).

ProjectCardsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
ColorSelector="@(p => p.IsClosed ? null : p.StatusColor)"
StripeIconSelector="@(p => p.IsLate ? IconNames.All.ExclamationCircleFill : null)"
CssClassSelector="@(p => p.IsLate ? "font-weight-bold" : null)">
<BodyContent Context="project">
<div class="d-flex">
<LgLabel Text="@project.Name" CssClass="mr-3" />
<LgLabel Text="@project.StatusLabel" CssClass="ml-auto" />
</div>
</BodyContent>
</LgListView>
ProjectCardsPage.razor.cs
public partial class ProjectCardsPage : LgPage
{
// Projects displayed: StatusColor (CSS color, e.g., "#62AC87" or "var(--bs-danger)") colors the stripe,
// a closed project (IsClosed) doesn't have one, and a late project (IsLate) is bolded and signaled
// by an icon in the stripe.
private readonly List<ProjectVm> _projects = new();

// Card model: the selectors and fragments of the list read its properties.
private sealed class ProjectVm
{
public string Name { get; set; }

public string StatusLabel { get; set; }

public string StatusColor { get; set; }

public bool IsClosed { get; set; }

public bool IsLate { get; set; }
}
}

Clickable cards and active item​

Cards become clickable (class card-clickable, keyboard focus) when the list receives an action:

  • OnItemClick (EventCallback<TItem>): triggered on clicking a card, with the clicked item.
  • @bind-ActiveItem (ActiveItem / ActiveItemChanged): the active item receives the class active; clicking a card makes its item active before triggering OnItemClick. Clicking on the already active card leaves it active. The active item is compared like selection, on KeyField (or the Id property of a remote list without KeyField): it remains active after a data reload (page change, remote list). Without binding (ActiveItem alone), the active item is only displayed.
  • LinkSelector (Func<TItem, LgPageLink>): page opened by the card. An item with a link navigates, without triggering OnItemClick or changing the active item; an item for which the selector returns null keeps the list's click behavior.

Two selectors complement each item's card: TooltipSelector (tooltip, in HTML format with TooltipIsHtml="true") and ConfirmationMessageSelector (confirmation message displayed before the click action: active item, OnItemClick, or link; no confirmation when it returns null). Selection remains independent of click: it is done by the checkbox (SelectableRows) or by ToggleSelectionAsync() from a template.

ProjectMasterDetailPage.razor
<div class="row">
<div class="col-8">
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
KeyField="@nameof(ProjectVm.Id)"
@bind-ActiveItem="_activeProject"
OnItemClick="OnProjectClickAsync"
ColorSelector="@(p => p.StatusColor)"
TooltipSelector="@(p => p.OwnerName)"
ConfirmationMessageSelector="@(p => p.IsLocked ? "#ConfirmOpenLockedProject" : null)" />
</div>
<div class="col-4">
@if (_activeProject is not null)
{
<LgLabel Text="@_activeProject.Name" />
}
</div>
</div>
ProjectMasterDetailPage.razor.cs
public partial class ProjectMasterDetailPage : LgPage
{
// Projects displayed: the list compares them on Id (KeyField) to find the active item after a reload.
private readonly List<ProjectVm> _projects = new();

// Active item (two-way binding): updated by the list on card click, before OnProjectClickAsync.
private ProjectVm _activeProject;

// Click on a card: the item is already active; a locked project only arrives here after confirmation.
private Task OnProjectClickAsync(ProjectVm project)
{
try
{
// Load project details...
}
catch (Exception ex)
{
ShowException(ex);
}
return Task.CompletedTask;
}

// Card model: Id identifies the project, other properties feed the card and its selectors.
private sealed class ProjectVm
{
public int Id { get; set; }

public string Name { get; set; }

public string OwnerName { get; set; }

public string StatusColor { get; set; }

public bool IsLocked { get; set; }

public override string ToString()
{
return Name;
}
}
}

Reusing the card in ItemTemplate (ListViewItemContext)​

The context of ItemTemplate is a ListViewItemContext<TItem>: in addition to the item, it exposes the elements of the default card built from the card parameters (BodyContent, StripeContent, the selectors, OnItemClick, ActiveItem...). The template can thus reuse the card, its color stripe, and its body by adding its own content.

MemberTypeDescription
ItemTItemItem to render.
IndexintPosition of the item (starting from 0) among the displayed items, i.e., in the current page with AllowPaging; it remains accurate in virtualized rendering.
IsSelectedboolIndicates whether the item is selected (always false without SelectableRows).
IsActiveboolIndicates whether the item is the active item (ActiveItem).
ColorstringColor returned by ColorSelector (null without selector).
CssClassstringCSS classes returned by CssClassSelector (null without selector). RenderCard applies them; otherwise, the template applies them where it wishes.
RenderCard(content)RenderFragmentLgCard of the item around free content: click (OnItemClick, active item), link, tooltip, confirmation, active class and CssClass, like the default card. With drag-and-drop, the handle (RenderDragHandle()) is rendered first in the card.
RenderDragHandle()RenderFragmentDrag-and-drop handle (button with a grip icon) when items can be moved (DragMode); null otherwise. Already rendered by RenderCard: call only in a template that doesn't use RenderCard (see Drag and drop).
RenderStripe()RenderFragmentColor stripe (LgCardStripe) of color Color, with classes from StripeCssClassSelector, icon from StripeIconSelector, and StripeContent (theme color without color or class); renders nothing when the item has neither color, stripe class, nor icon, and StripeContent is not set.
RenderBody()RenderFragmentCard body: a div.card-body containing BodyContent, or item.ToString() if absent.
ActivateAsync()TaskMakes the item active (ActiveItemChanged is triggered), without triggering OnItemClick; has no effect when it already is.
ToggleSelectionAsync()TaskSelects the item, or deselects it if already selected, like its checkbox (OnRowSelection is triggered); has no effect without SelectableRows.

The context displays as the item (@context renders item.ToString()).

RenderCard keeps the behavior of the list's card (click, active item...) while letting the template write its content:

ProjectActionsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
@bind-ActiveItem="_activeProject"
ColorSelector="@(p => p.StatusColor)">
<BodyContent Context="project">
<LgLabel Text="@project.Name" />
</BodyContent>
<ItemTemplate Context="card">
@card.RenderCard(
@<div class="d-flex w-100">
@card.RenderStripe()
@card.RenderBody()
<div class="card-body flex-grow-0">
<LgButton Text="#ArchiveProject" OnClick="@(() => ArchiveProjectAsync(card.Item))" />
</div>
</div>)
</ItemTemplate>
</LgListView>

To toggle selection on click, the template writes its own card and calls ToggleSelectionAsync():

ProjectCardTemplatePage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
SelectableRows="true"
ColorSelector="@(p => p.StatusColor)"
CssClassSelector="@(p => p.IsLate ? "font-weight-bold" : null)">
<BodyContent Context="project">
<LgLabel Text="@project.Name" />
</BodyContent>
<ItemTemplate Context="card">
<div class="card card-clickable @card.CssClass" @onclick="card.ToggleSelectionAsync">
@card.RenderStripe()
@card.RenderBody()
<div class="card-body">
<LgButton Text="#OpenProject"
OnClick="@(() => OpenProjectAsync(card.Item))" />
</div>
</div>
</ItemTemplate>
</LgListView>
ProjectCardTemplatePage.razor.cs
public partial class ProjectCardTemplatePage : LgPage
{
// Projects displayed: StatusColor colors the stripe and IsLate bolds the card (card.CssClass).
private readonly List<ProjectVm> _projects = new();

// Template-specific action: the button receives the item through context (card.Item). LgButton stops
// click propagation by default: only clicking elsewhere on the card toggles its selection.
private Task OpenProjectAsync(ProjectVm project)
{
try
{
// Open the project...
}
catch (Exception ex)
{
ShowException(ex);
}
return Task.CompletedTask;
}

// Card model: the selectors and body of the list read its properties.
private sealed class ProjectVm
{
public string Name { get; set; }

public string StatusColor { get; set; }

public bool IsLate { get; set; }
}
}

Grid layout​

By default, items are stacked across the full width. ItemMinWidth (CSS length, e.g., "18rem") arranges them in a grid: as many columns as the list width allows, each item measuring at least ItemMinWidth (unless the list is narrower), and cards in the same row take the same height. The grid applies to the default card like to ItemTemplate; it is ignored with Virtualize, which renders items line by line.

ProjectTilesPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
ItemMinWidth="16rem"
ColorSelector="@(p => p.StatusColor)">
<BodyContent Context="project">
<LgLabel Text="@project.Name" CssClass="font-weight-bold d-block" />
<LgLabel Text="@project.OwnerName" CssClass="d-block" />
</BodyContent>
</LgListView>

Declarative sorting with LgListViewSort​

Each sortable field is declared by an LgListViewSort component in the SortOptions section; the sort menu of the header is generated from these declarations. Its label indicates the current sort ("Sort by: Name") and an arrow its direction (↑ ascending, ↓ descending, like the headers of LgGridView columns); it offers the declarations then the "Ascending" and "Descending" directions, grayed out as long as no sort is chosen. Sorting is applied by the data pipeline (client-side locally, server-side remotely).

  • SortSelector is a typed expression x => x.Member, like the SortSelector of LgGridView columns; the type TItem is inferred from the enclosing LgListView (it is not to be written). A value-type key is automatically "unboxed" to remain translatable to a remote query.
  • Sort key: the path of the member (x => x.Owner.Name gives Owner.Name). It identifies the sort in persisted state (StateId) and in OnSortChanged (Key). For a computed expression (x => x.Quantity * x.UnitPrice, which only works locally), set Key: without a key, an exception is raised. Two declarations cannot have the same key.
  • Label: Text is optional; if absent, the Name of the [Display] attribute of the sorted member is used, then the key.
  • Initial sort: the first declaration marked IsDefault="true". Without a default declaration, the list is not sorted initially (items keep the source order until a sort is chosen).
SortedProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
OnSortChanged="OnSortChangedAsync">
<SortOptions>
<LgListViewSort SortSelector="@(x => x.Name)" Text="#ProjectName" IsDefault="true" />
<LgListViewSort SortSelector="@(x => x.Status)" />
<LgListViewSort SortSelector="@(x => x.Name.Length)" Key="NameLength" Text="#ProjectNameLength" />
</SortOptions>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
SortedProjectsPage.razor.cs
public partial class SortedProjectsPage : LgPage
{
private readonly List<ProjectVm> _projects = new()
{
new ProjectVm { Name = "Lagoon Portal", Status = ProjectStatus.Active },
new ProjectVm { Name = "Lagoon Archive", Status = ProjectStatus.Closed }
};

// Reacts to sort change: useful to synchronize external state (URL, analytics…).
private Task OnSortChangedAsync(ListViewSortEventArgs args)
{
// args.Key: sort key ("Name", "Status", "NameLength"; null if no sort);
// args.SortDirection: Asc or Desc (None if no sort).
// args.Sorts: the same sort as LgGridView form (0 or 1 pair (Key, SortDirection)).
return Task.CompletedTask;
}

private sealed class ProjectVm
{
public string Name { get; set; }

// Label of sort declared without Text.
[Display(Name = "#ProjectStatus")]
public ProjectStatus Status { get; set; }
}

private enum ProjectStatus
{
Active,
Closed
}
}

Pagination​

AllowPaging activates the built-in pager, presented like that of LgGridView: size selector, page buttons, and with DisplayInputPageSelector, "go to page" field, grouped on the right. Like in the grid, the pager does not display the item count: place {0} in Title (see Header) or bind ListViewDataCounter. DefaultPageSize must belong to PaginationSizeSelector (otherwise the first value of the selector applies); the value 0 in the selector proposes "All" (and can be the initial size). Changing AllowPaging or PaginationSizeSelector (a size no longer offered is replaced by the first of the selector) reloads the list from the first page. CurrentPage is bindable in two-way. A sort or filter change automatically returns to the first page. Like in the grid, with Items the filtered and sorted result is computed once then reused by page and page-size changes: it is recomputed when filters, sort, grouping, or source change (other collection, different number of items, event from an ObservableCollection), and by RefreshAsync(), to call after modifying items in place. Like for LgGridView, PaginationButtonCount sets the number of page buttons, DisplayInputPageSelector adds a numeric "go to page" field (validated by Enter; an out-of-bounds number is brought back to the first or last page), PagerOnTop places the pager above items, and ListViewDataCounter (bindable in two-way) exposes after each load the number of displayed items (ActiveRows), number of pages (TotalPages), and total number of items (TotalRows); it is notified only when a counter changes.

PagedProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
AllowPaging="true"
DefaultPageSize="20"
DisplayInputPageSelector="true"
@bind-CurrentPage="_currentPage"
@bind-ListViewDataCounter="_counter">
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
PagedProjectsPage.razor.cs
public partial class PagedProjectsPage : LgPage
{
// Current page bound in two-way: allows, for example, restoring the page from the URL.
private int _currentPage = 1;

// Counters updated after each load (e.g., display _counter?.TotalRows in the title).
private ListViewDataCounter _counter;

// Local source paginated client-side by the data pipeline.
private readonly List<ProjectVm> _projects = new();

private sealed class ProjectVm
{
public string Name { get; set; }
}
}

Declarative filters​

The Filters section hosts LgListViewFilter components actually rendered in a collapsible panel above the list. Each filter displays the filter box of LgGridView corresponding to the type of its FilterSelector (the typed expression x => x.Member also infers the type of the filtered value):

Value typeFilter box
stringtext: value selection or condition (contains, starts with, ends with)
bool / bool?boolean
enumeration (nullable or not)enumeration value selection
numeric (int, decimal, double…)value selection or condition (equal, between, greater…)
DateTime / DateTimeOffsetdate (selection, periods, conditions)
TimeSpantime (conditions)
other typevalue selection

The "Selection" tab offers values from the source filtered by the other filters of the list (like grid columns), or values from Items when declared. In remote mode, these values are available only for a simple member (x => x.Member).

Like for sorting, the key of the filter is the member path (or Key, required for a computed expression) and the label comes from Text, if absent from the [Display] of the member, then from the key. The "Filters" button of the header shows or hides the panel and indicates the number of active filters; this button and panel are displayed only when Filters contains at least one LgListViewFilter (an empty fragment, or where all filters are excluded by an @if, hides them); when the panel is displayed, the "Clear" button placed beside it empties all filters (it is grayed out as long as no filter is active), as does the ClearFiltersAsync method by code. Active filters are combined and applied by the data pipeline, client-side and server-side alike.

With ShowFiltersSummary="true", active filters are summarized under the title, like with ShowFiltersSummary of LgGridView: the first two in the form "Label: value" (the value as displayed by the filter box, with a tooltip), the rest counted in a "+N" item whose tooltip lists them. The summary is displayed only when the filter panel is hidden (open, the panel already shows the values), and disappears when no filter is active. It adopts the appearance of the grid summary in each theme.

Filter panel visibility follows the same contract as LgGridView: ShowFilters is bindable in two-way (@bind-ShowFilters) and its value is preserved, unless DefaultShowFilters is set, which then takes precedence on first render. Unlike the grid, hiding the panel preserves filter values (they remain applied and counted on the "Filters" button).

Filters are arranged in a grid across the full width (in a column in drawers); above items, they are grouped in a tinted band. Each box looks like a dropdown list (chevron), "(no filter)" grayed out; a filter with a value is highlighted (label and border in the theme's accent color) and bears a cross that only empties that filter (reload and OnFilterChanged, like an input). Colors and dimensions are SCSS variables of the theme ($list-view-filter-*, $list-view-filters-bg…).

FiltersPosition chooses where the panel displays (see ListViewFiltersPosition):

  • Top (default): above items, in the list; the "Clear" button is in the action bar.
  • Popup: in a centered modal window, with the appearance and grayed background of an LgModal;
  • Left / Right: in a full-height drawer that slides from the left or right edge of the screen, over the page, with filters stacked in one column.

In popup and drawer, the "Filters" button opens the window, which has the title "Filters", its "Clear" and "Close" buttons and a close cross; it also closes with Esc or a click outside. Filter boxes open normally above the window. Closed, the window is only hidden: filters keep their values and remain applied (displayed by the summary with ShowFiltersSummary), and changing FiltersPosition on the fly also preserves values. An open window is not reopened by persisted state (StateId) on next display.

DrawerFilteredProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
FiltersPosition="ListViewFiltersPosition.Right"
ShowFiltersSummary="true">
<Filters>
<LgListViewFilter FilterSelector="@(x => x.Name)" Text="#ProjectName" />
<LgListViewFilter FilterSelector="@(x => x.Owner)" Text="#ProjectOwner" />
</Filters>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>

OnFilterChanged receives a ListViewFilterChangedEventArgs whose Filters contains active filters indexed by key, and HasFilters() indicates if at least one remains, like GridViewFilterChangedEventArgs. The event is triggered only when the set of active filters changes (validating the same filter or clearing already empty filters does not trigger it), including when values are restored from StateId.

FilteredProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
@bind-ShowFilters="_showFilters"
ShowFiltersSummary="true"
OnFilterChanged="OnFilterChangedAsync">
<Filters>
<LgListViewFilter FilterSelector="@(x => x.Name)" Text="#ProjectName" />
<LgListViewFilter FilterSelector="@(x => x.Owner)" Text="#ProjectOwner" Items="_owners" />
<LgListViewFilter FilterSelector="@(x => x.Status)" />
<LgListViewFilter FilterSelector="@(x => x.DueDate)" Text="#ProjectDueDate" />
</Filters>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
FilteredProjectsPage.razor.cs
public partial class FilteredProjectsPage : LgPage
{
private readonly List<ProjectVm> _projects = new();

// Values offered by the owner filter, instead of values from the source.
private readonly string[] _owners = { "Anne Birney", "John Valdez" };

// Filter panel visibility, bound in two-way (displayed on first render).
private bool _showFilters = true;

// Reacts to active filter change: args.Filters indexes them by key ("Name", "Status"…),
// args.HasFilters() is false when all filters are cleared.
private Task OnFilterChangedAsync(ListViewFilterChangedEventArgs args)
{
return Task.CompletedTask;
}

private sealed class ProjectVm
{
public string Name { get; set; }

public string Owner { get; set; }

// Label of filter declared without Text.
[Display(Name = "#ProjectStatus")]
public ProjectStatus Status { get; set; }

public DateTime DueDate { get; set; }
}

private enum ProjectStatus
{
Active,
Closed
}
}

Selection with action bar​

Like LgGridView, SelectableRows="true" activates selection checkboxes; Selection receives the collection of selected items (a collection is created if it is omitted). KeyField designates the property that identifies an item: selection then compares items on this key and survives reloads (page change in remote mode in particular). Without KeyField, a remote list (ControllerUri) uses the Id property of the model when it has one, even if the model redefines equality (Id must then uniquely identify the item); otherwise, and for a local list, equality of the type (Equals / IEquatable<T>) is used. The key follows a change of KeyField or data source (local or remote).

The "Select all" checkbox is placed in the header, before the title, in the column of item checkboxes. It is checked when all loaded items are selected, indeterminate when only some are. Clicking the checked checkbox deselects all; otherwise it selects loaded items, without duplicating already selected ones. It is grayed out as long as the list contains no items, and hidden when the list is collapsed. Toolbar is displayed in the header, while ToolbarSelection feeds the action panel visible as soon as at least one item is selected; like in the grid, it displays between items and the bottom pager.

SelectableProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
SelectableRows="true"
Selection="_selectedProjects"
KeyField="@nameof(ProjectVm.Id)"
OnRowSelection="OnRowSelectionAsync"
Title="#ProjectsTitle">
<Toolbar>
<LgToolbarButton Text="#AddProject" IconName="@IconNames.All.Plus" OnClick="AddProjectAsync" />
</Toolbar>
<ToolbarSelection>
<LgToolbarGroup Kind="ToolbarGroupKind.Primary">
<LgToolbarButton Text="#ArchiveSelection"
IconName="@IconNames.All.Archive"
OnClick="ArchiveSelectedAsync" />
</LgToolbarGroup>
</ToolbarSelection>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
SelectableProjectsPage.razor.cs
public partial class SelectableProjectsPage : LgPage
{
// Main source for the list: actions can add, remove, or modify items in it.
private readonly List<ProjectVm> _projects = new()
{
new ProjectVm { Id = 1, Name = "Lagoon Portal" },
new ProjectVm { Id = 2, Name = "Lagoon Mobile" }
};

// Stores checked items: the reference must remain stable for the component to update it.
private readonly List<ProjectVm> _selectedProjects = new();

// Reacts to each selection change: args.SelectAction distinguishes individual selection
// from "select all" / "deselect all".
private Task OnRowSelectionAsync(ListViewSelectionEventArgs<ProjectVm> args)
{
return Task.CompletedTask;
}

// Adds an item: the component detects the change in number and reloads the list.
private Task AddProjectAsync(ActionEventArgs args)
{
_projects.Add(new ProjectVm { Id = _projects.Count + 1, Name = "Lagoon Back Office" });
return Task.CompletedTask;
}

// Processes the current selection: clearing the list avoids keeping already archived items.
private Task ArchiveSelectedAsync(ActionEventArgs args)
{
_selectedProjects.Clear();
ShowSuccess("#ProjectsArchived");
return Task.CompletedTask;
}

// Identifiable model: the Id property serves as the selection key via KeyField.
private sealed class ProjectVm
{
public int Id { get; set; }

public string Name { get; set; }
}
}

Grouping​

GroupSelector (Expression<Func<TItem, object>>, e.g., x => x.Status) groups displayed items under a collapsible header. The list sorts first by group, then by the chosen sort from SortOptions: items of a group remain consecutive, including in remote mode (ControllerUri), where this sort is sent to the server. Groups are sorted by GroupOrderSelector when set (the rank of a status grouped by label, for example), then by key, in ascending order. Like SortSelector, a computed expression only works locally.

  • Default header: the group key (the [Display] display name of an enumeration value, "(Empty)" for a null key) and the number of items in the group. GroupHeaderContent replaces this content; GroupColorSelector (Func<TItem, string>, called with the first item of the group) adds a color stripe to the header.
  • Collapse: clicking the header (or its button, by keyboard) collapses or expands the group. Like on a grouped LgGridView, the list header has two buttons "Expand all groups" and "Collapse all groups" (also accessible by ExpandAllGroups() / CollapseAllGroups()), which apply to all groups, including those collapsed or expanded one by one; these buttons make the list header display even without a title. DefaultGroupCollapsed="true" collapses all groups initially. GroupCollapsable="false" prevents collapsing groups (e.g., in a short editor where everything must stay visible): the header no longer has a collapse button and is no longer clickable, the two list buttons are not displayed, and groups remain expanded. Collapsed groups are remembered by key as long as the list is displayed (page change, sort change, or reload included) and, with StateId, persisted for the next display (see State persistence).
  • Selection: with SelectableRows, the header has a checkbox that selects displayed items of the group, or deselects them when they all are (OnRowSelection with SelectGroup / UnselectGroup). It is checked when the whole group is selected and marked partial when only some are.
  • Pagination and virtualization: groups are computed on displayed items, i.e., those of the current page with AllowPaging; a group split by pagination resumes at the head of the next page. With Virtualize, group headers are lines virtualized like items. With ItemMinWidth, each group has its own grid.
  • Presentation: the header is a rounded band, with the group name in bold and the item count in a badge. With GroupColorSelector, the band is tinted with the group color and the name takes a darker shade; the color is also exposed as CSS variable --list-view-group-color on the header, for your own styles. The header remains stuck at the top of the scrolling area (the page, or the list when it has a height) as you browse the items of its group — except in virtualization, where a header that leaves the visible area is no longer rendered. Items of a group are indented under its header: only their content is offset, checkboxes remaining aligned with the header's (in grid layout, it's the whole grid of the group). SCSS variables: $list-view-group-header-tint, $list-view-group-text-shade, $list-view-group-header-radius, $list-view-group-spacing (extra space between two groups, null by default), $list-view-group-indent (indent of items, 1.5rem by default).

GroupHeaderContent receives a ListViewGroupContext<TItem>:

MemberTypeDescription
KeyobjectGroup key returned by GroupSelector.
TextstringDisplay text of the key (enumeration display name, "(Empty)" for null, ToString() otherwise); the context displays as this text.
ItemsIReadOnlyList<TItem>Displayed items of the group (those of the current page with AllowPaging).
CountintNumber of displayed items in the group.
ColorstringColor returned by GroupColorSelector for the first item of the group (null without selector).
IsCollapsedboolIndicates whether the group is collapsed.
GroupedProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
SelectableRows="true"
KeyField="@nameof(ProjectVm.Id)"
GroupSelector="@(p => p.StatusLabel)"
GroupOrderSelector="@(p => p.StatusRank)"
GroupColorSelector="@(p => p.StatusColor)"
ColorSelector="@(p => p.StatusColor)">
<SortOptions>
<LgListViewSort SortSelector="@(x => x.Name)" Text="#ProjectName" IsDefault="true" />
</SortOptions>
<GroupHeaderContent Context="group">
<div class="d-flex">
<LgLabel Text="@group.Text" CssClass="mr-3" />
<LgLabel Text="@("ProjectCount".Translate(group.Count))" CssClass="ml-auto" />
</div>
</GroupHeaderContent>
<BodyContent Context="project">
<LgLabel Text="@project.Name" />
</BodyContent>
</LgListView>
GroupedProjectsPage.razor.cs
public partial class GroupedProjectsPage : LgPage
{
// Projects displayed: grouped by status label, groups following status rank (StatusRank)
// and items of a group following the sort by name.
private readonly List<ProjectVm> _projects = new();

// Card model: StatusLabel is the group key, StatusRank the order of groups, and StatusColor the color
// of the card stripe and group header.
private sealed class ProjectVm
{
public int Id { get; set; }

public string Name { get; set; }

public string StatusLabel { get; set; }

public int StatusRank { get; set; }

public string StatusColor { get; set; }
}
}

Drag and drop​

DragMode (flags ListViewDragMode) activates drag-and-drop of items: Reorder to reorder the list, DragOut / DropIn to exchange items with other lists of the same DragGroup (and same type TItem), Copy to copy instead of move. Items move via a handle displayed to the left of their card, before the color stripe, by mouse, touch, or keyboard; on a touch screen, a long press (about half a second, without moving your finger) anywhere on the card also starts dragging, outside fields, links, and card buttons: a short press remains a click, and quick scrolling scrolls the page. With DragFromItem="true", the mouse (or stylus) also moves an item from any point on its card, with the same exclusions (fields, links, buttons, elements with role button): a click without movement remains a click, and the card text is no longer selectable. The handle remains displayed for the keyboard. During hover, an insertion line indicates the drop location (vertical between two cards of a grid); a list that doesn't choose the position (without Reorder, sorted, or empty) is fully highlighted and receives the item at the end. No dependency is added: the component's JavaScript engine uses Pointer Events.

ReorderPage.razor
<LgListView TItem="ProjectVm" Items="_projects" DragMode="ListViewDragMode.Reorder"
OnItemDropped="SaveOrderAsync">
<BodyContent Context="project">
<LgLabel Text="@project.Name" />
</BodyContent>
</LgListView>

Item acceptance is decided at three levels, which combine:

  1. Modes and group, evaluated in the browser without a round-trip: the source list must have DragOut, the target DropIn, and both the same DragGroup; within a list, Reorder is necessary, and an active sort cancels it (sort decides the order).
  2. CanDrop of the target list, called during hover for each position (the result is memorized during dragging) with a ListViewDropContext<TItem>: a refused position displays no line, the dragged card is framed in red, and the cursor becomes "forbidden".
  3. OnItemDrop of the target list, on release, before update: Cancel = true refuses the drop (the item returns to its place), allowing asynchronous verification (server call, confirmation).
SprintPage.razor
<LgListView TItem="ProjectVm" Items="_backlog" DragMode="ListViewDragMode.All" DragGroup="sprint" />
<LgListView TItem="ProjectVm" Items="_sprint" DragMode="ListViewDragMode.All" DragGroup="sprint"
CanDrop="@(c => c.IsSameList || _sprint.Count < 5)" OnItemDropped="StateHasChanged" />

Data update. Without Cancel or Handled, the list updates its local items itself (Items mutable): removal from source list on a move between lists, insertion before the new next item (IList<TItem>; addition at end for other ICollection<TItem>), with in Copy mode the copy created by ItemCopyFactory of the source list (the instance itself if absent). The handler of OnItemDrop that updates data itself sets Handled = true: the list then only reloads. Items loaded by ControllerUri are never modified: the handler updates the remote source then calls RefreshAsync(). A list that cannot modify its items (ControllerUri, array, or other read-only collection) thus only accepts items from other lists with an OnItemDrop handler. OnItemDropped is then triggered, once the item is in place (to record the new order, for example); it also causes the parent to render.

PlanPage.razor.cs
// <LgListView ... DragMode="ListViewDragMode.DragOut | ListViewDragMode.Copy" DragGroup="templates" ItemCopyFactory="CopyProject" />
private ProjectVm CopyProject(ProjectVm template)
{
return new ProjectVm() { Id = ++_lastId, Name = template.Name };
}

Grouped lists. With GroupSelector, an item can be dropped in another group (or a collapsed group, at its end) only if OnItemDrop is wired: it is the handler that changes the grouped property of the item from TargetGroupKey (IsGroupChanged indicates a group change); the list then places the item at the drop position.

StatusPage.razor.cs
// <LgListView ... DragMode="ListViewDragMode.Reorder" GroupSelector="@(p => p.Status)" OnItemDrop="OnStatusDropAsync" />
private async Task OnStatusDropAsync(ListViewDropEventArgs<ProjectVm> e)
{
if (!e.IsGroupChanged)
{
return;
}
ProjectStatus status = (ProjectStatus)e.TargetGroupKey;
if (!await ProjectService.CanChangeStatusAsync(e.Item, status))
{
e.Cancel = true;
return;
}
e.Item.Status = status;
}

Custom template. RenderCard renders the handle in the card; an ItemTemplate that builds its own rendering calls RenderDragHandle() where desired (by mouse, dragging only starts from the handle; by touch, long press works on the entire item):

<ItemTemplate Context="item">
<div class="d-flex align-items-center">
@item.RenderDragHandle()
<span>@item.Item.Name</span>
</div>
</ItemTemplate>

Keyboard. From a handle, Space or Enter seizes the item, arrows choose its position (up / down a grid line, Home / End), Space or Enter drops it, and Esc cancels; Ctrl + arrow moves it directly one position. Positions and result are announced to screen readers. Without Reorder, the keyboard cannot move anything: handles are then outside the tab order and hidden from assistive technologies. The keyboard reorders the item in its list (including from one group to another); moving to another list is done by mouse or touch (or by application actions).

ListViewDropContext<TItem>​

Drop position passed to CanDrop; ListViewDropEventArgs<TItem>, received by OnItemDrop and OnItemDropped, inherits from it and adds Cancel and Handled.

MemberTypeDescription
ItemTItemDragged item.
Source / TargetLgListView<TItem>Original list of the item / list receiving it.
SourceIndexintPosition of the item among displayed items of the source list.
TargetIndexintInsertion position among displayed items of the target list, before the move (in the same list, SourceIndex and SourceIndex + 1 designate the current place).
PreviousItem / NextItemTItemDisplayed items just before / after the insertion position (dragged item excluded, in the target group); default value at start / end.
SourceGroupKey / TargetGroupKeyobjectGroup key of the item in the source list / of the group receiving it (null without grouping).
IsSameListboolThe item is moved in its own list.
IsGroupChangedboolThe item is dropped in another group than its own.
IsCopyboolThe item is copied (Copy on the source list).
Cancelbool(ListViewDropEventArgs) Refuse the drop: the item returns to its place.
Handledbool(ListViewDropEventArgs) The handler updated items: the list only reloads.
Hover predicate

CanDrop is called synchronously from the browser, which Blazor WebAssembly allows; without possible synchronous call, positions are accepted on hover and verified on release.

Remote list with ControllerUri​

Use ControllerUri to delegate filtering, sorting, and pagination to the server: the list sends $qd requests to the [Queryable] controller, exactly like LgGridView. Items is ignored in this mode. A change in ControllerUri reloads the list. ControllerQueryArg transmits an additional business argument; its modification reloads the list (comparison by Equals, on a clone if the argument implements ICloneable, like for LgGridView). A new load cancels the current one, and only the response from the last load started is displayed. AllowCancellation allows the user to cancel a long load then restart it.

OrdersRemotePage.razor
<LgListView TItem="OrderVm"
ControllerUri="api/Orders"
ControllerQueryArg="_queryArg"
AllowCancellation="true"
AllowPaging="true"
KeyField="@nameof(OrderVm.Id)"
Title="#OrdersTitle">
<ItemTemplate Context="order">
<LgCard CssClass="mb-2">
<LgLabel Text="@order.Item.Number" />
<LgLabel Text="@order.Item.CustomerName" CssClass="ml-2" />
</LgCard>
</ItemTemplate>
</LgListView>
OrdersRemotePage.razor.cs
public partial class OrdersRemotePage : LgPage
{
// Argument serialized in remote requests to apply a business filter server-side.
private readonly OrdersQueryArg _queryArg = new()
{
CustomerId = 42,
};

private sealed class OrdersQueryArg
{
public int CustomerId { get; set; }
}
}

Endpoint contract​

  • Route: POST api/Orders/$qd
  • Body: DataQueryRequest<OrdersQueryArg>
  • Return: IQueryable<OrderVm> request decorated with [Queryable]
OrdersController.cs
[Route("api/[controller]")]
public class OrdersController : LgControllerBase
{
private readonly AppDbContext _db;

public OrdersController(AppDbContext db)
{
_db = db;
}

// Provides the remote source: the Queryable attribute applies filters, sorts, and pages sent by the list.
[HttpPost("$qd")]
[Queryable]
public IActionResult GetOrders([FromBody] DataQueryRequest<OrdersQueryArg> args)
{
try
{
IQueryable<OrderVm> query = _db.Orders.Select(o => new OrderVm
{
Id = o.Id,
Number = o.Number,
CustomerName = o.Customer.Name,
CustomerId = o.CustomerId,
});
if (args.Arg?.CustomerId is int customerId)
{
query = query.Where(o => o.CustomerId == customerId);
}
return Ok(query);
}
catch (Exception ex)
{
return Problem(ex);
}
}
}

Height and scrolling in the list​

Like LgGridView, give the list a height via its style attribute (height or max-height): items then scroll within the list, while the header, filters displayed above items, action panel, and pager remain visible. A page change, page size change, sort, or filter change brings the item area to the top. Without height, the list grows with its items and scrolls with the page.

ScrollableProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
AllowPaging="true"
style="height: 600px">
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>
Height by CSS class

Scrolling in the list is activated only if the height is declared in the style attribute. A height given by a CSS class (CssClass) is not detected: the list takes this height, but its items don't scroll in it.

Virtualization​

For large lists, Virtualize="true" renders only visible items (Blazor Virtualize component on loaded data). VirtualizeItemSize indicates the expected height of an item in pixels. Like LgGridView, virtualization combines with AllowPaging: the items of the current page are then virtualized (useful with large pages, or "All" size). The Virtualize component scrolls with the closest scrolling ancestor (overflow-y: auto or scroll): by default it's the document. To scroll the list itself, give it a height via its style attribute (see Height and scrolling in the list): only items visible in the list are then rendered.

Scrolling container height

A scrolling container whose height is not constrained grows with its content: Virtualize then considers all items visible and renders them all, canceling virtualization.

VirtualizedProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
Title="#ProjectsTitle"
Virtualize="true"
VirtualizeItemSize="72"
style="height: 600px">
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>

State persistence with StateId​

When StateId is set, the sort (key and direction), page size, filter panel visibility (restored for Top position only), filters, and collapsed groups are persisted in the browser's local storage and restored on next display (filters are indexed by their key). Unreadable persisted state is ignored (and traced) without blocking load; a persisted sort key no longer declared in SortOptions is ignored in favor of the initial sort, a persisted filter whose type no longer matches the filter box (member type changed) is ignored, and collapsed groups are restored only for the same grouping (same GroupSelector and GroupOrderSelector expressions); a grouping changed on the fly restarts from DefaultGroupCollapsed. When state contains filter values, the first load waits for them to be restored: a single request, already filtered, is emitted. Each persisted value is applied only once: a filter component recreated later (in an @if of Filters) keeps the current value. Removing an active filter component reloads the list without that filter. Like when loading a LgGridView profile, restoring filters triggers OnFilterChanged, and a restored panel visibility different from ShowFilters is notified by ShowFiltersChanged.

PersistedProjectsPage.razor
<LgListView TItem="ProjectVm"
Items="_projects"
StateId="projects-list"
AllowPaging="true">
<SortOptions>
<LgListViewSort SortSelector="@(x => x.Name)" Text="#ProjectName" IsDefault="true" />
</SortOptions>
<Filters>
<LgListViewFilter FilterSelector="@(x => x.Name)" Text="#ProjectName" />
</Filters>
<ItemTemplate Context="project">
<LgCard CssClass="mb-2">
<LgLabel Text="@project.Item.Name" />
</LgCard>
</ItemTemplate>
</LgListView>

Properties​

All [Parameter] properties of the component, including inherited ones.

LgListView<TItem>​

NameTypeDefaultDeclared inDescription
ActiveItemTItemdefaultLgListView<TItem>Active item (class active on its card), bindable in two-way via ActiveItemChanged; bound, it changes on card click. Compared like selection (see KeyField).
AdditionalAttributesIReadOnlyDictionary<string, object>nullLgListView<TItem>Additional attributes applied to the root container (the frame).
AllowCancellationboolfalseLgListView<TItem>Allows the user to cancel an ongoing remote load (then restart it).
AllowPagingboolfalseLgListView<TItem>Activates pagination and built-in pager.
BodyContentRenderFragment<TItem>nullLgListView<TItem>Content of the body of the default card (and of RenderBody() in ItemTemplate); if absent, item.ToString() is displayed.
CollapsableboolfalseLgListView<TItem>Allows the list to be collapsed by clicking its header.
CollapsedboolfalseLgListView<TItem>Collapsed state, bindable in two-way via CollapsedChanged (has effect only with Collapsable).
ColorSelectorFunc<TItem, string>nullLgListView<TItem>CSS color of the card's color stripe (Color in ItemTemplate); without color, the stripe keeps the theme color (it is rendered when this selector, StripeCssClassSelector, or StripeIconSelector returns a value, or with StripeContent).
ConfirmationMessageSelectorFunc<TItem, string>nullLgListView<TItem>Confirmation message displayed before the card click action of an item; no confirmation when it returns null or empty string.
ControllerQueryArgobjectnullLgListView<TItem>Additional business argument serialized in each remote request.
ControllerUristringnullLgListView<TItem>URI of the [Queryable] controller providing data; activates remote mode (Items is then ignored).
CssClassstringnullLgListView<TItem>CSS classes added to the root container (the frame).
CssClassSelectorFunc<TItem, string>nullLgListView<TItem>CSS classes added to an item's default card (CssClass in ItemTemplate, to be applied by the template).
CanDropFunc<ListViewDropContext<TItem>, bool>nullLgListView<TItem>Indicates whether a dragged item can be dropped at a position in this list (target list), called during hover (see Drag and drop).
CurrentPageint0LgListView<TItem>Current page index (1 = first page), bindable in two-way via CurrentPageChanged.
DataErrorTitlestring#lblListViewErrorTitleLgListView<TItem>Title displayed when data loading fails.
DefaultCollapsedbool?nullLgListView<TItem>Initial collapsed state; when set, it replaces the initial value of Collapsed.
DefaultGroupCollapsedboolfalseLgListView<TItem>Collapses all groups initially (with GroupSelector).
DefaultPageSizeint?nullLgListView<TItem>Initial page size (0 = "All"); must belong to PaginationSizeSelector, otherwise the first value of the selector applies.
DefaultShowFiltersbool?nullLgListView<TItem>Initial filter panel visibility; when set, it replaces the initial value of ShowFilters.
DisplayInputPageSelectorboolfalseLgListView<TItem>Adds to the pager a numeric "go to page" field (validated by Enter).
DragFromItemboolfalseLgListView<TItem>Mouse or stylus moves an item from any point on its card, not only from its handle (outside fields, links, buttons); touch keeps long press, keyboard keeps handle. See Drag and drop.
DragGroupstringnullLgListView<TItem>Name of the group of lists that exchange items (DragOut / DropIn); without group, items can only be reordered in the list.
DragModeListViewDragModeNoneLgListView<TItem>Drag-and-drop capabilities (flags): reordering, exit to / entry from lists of the same DragGroup, copying.
FiltersRenderFragmentnullLgListView<TItem>Filter declarations (LgListViewFilter components), rendered in the collapsible panel.
FiltersPositionListViewFiltersPositionTopLgListView<TItem>Position of the filter panel: above items, in a modal window, or in a drawer on the left or right.
GroupCollapsablebooltrueLgListView<TItem>Allows collapsing and expanding groups (header click, "Expand all groups" / "Collapse all groups" buttons). When false, groups remain expanded: no collapse button, header not clickable, DefaultGroupCollapsed and CollapseAllGroups() have no effect.
GroupColorSelectorFunc<TItem, string>nullLgListView<TItem>CSS color of a group header stripe, called with the first item of the group; no stripe when it returns null or empty string.
GroupHeaderContentRenderFragment<ListViewGroupContext<TItem>>nullLgListView<TItem>Content of a group header (see Grouping); if absent, the group key and item count.
GroupOrderSelectorExpression<Func<TItem, object>>nullLgListView<TItem>Order of groups (ascending); if absent, groups are sorted by key. Ignored without GroupSelector.
GroupSelectorExpression<Func<TItem, object>>nullLgListView<TItem>Group key of an item x => x.Member: groups displayed items under collapsible headers, the list sorting first by group (also server-side).
IconNamestringnullLgListView<TItem>Icon displayed before the title.
ItemCopyFactoryFunc<TItem, TItem>nullLgListView<TItem>Creates the copy of an item dragged from this list to another in Copy mode; if absent, the item itself is inserted.
ItemMinWidthstringnullLgListView<TItem>Minimum width of an item (CSS length, e.g., "18rem"): arranges items in a grid. Ignored with Virtualize.
ItemTemplateRenderFragment<ListViewItemContext<TItem>>nullLgListView<TItem>Item rendering template, takes precedence over default card; its context exposes the item (Item) and card elements (see ListViewItemContext).
ItemsICollection<TItem>nullLgListView<TItem>Local source of items. Ignored when ControllerUri is set. Filtered and sorted result is cached between page changes: call RefreshAsync() after modifying items in place.
KeyFieldstringnullLgListView<TItem>Property identifying an item: selection and active item compare on this key and survive reloads, and each item keeps its components (render key @key) when it changes place. If absent, a remote list uses the Id property of the model if it has one, otherwise type equality is used. Key follows a change of data source (local or remote).
KindKindKind.PrimaryLgListView<TItem>Visual theme of the list frame.
LinkSelectorFunc<TItem, LgPageLink>nullLgListView<TItem>Page opened by clicking an item's card; an item with a link navigates without triggering OnItemClick or changing the active item.
ListViewDataCounterListViewDataCounternullLgListView<TItem>Counters from the last load (ActiveRows, TotalPages, TotalRows), bindable in two-way via ListViewDataCounterChanged.
NoDataDescriptionstring#lblListViewNoDataDescLgListView<TItem>Description displayed when the source contains no items.
NoDataTitlestring#lblListViewNoDataTitleLgListView<TItem>Title displayed when the source contains no items.
PagerOnTopboolfalseLgListView<TItem>Displays the pager above items rather than below.
PaginationButtonCountint5LgListView<TItem>Number of page buttons displayed by the pager.
PaginationSizeSelectorint[]{ 10, 20, 50, 100 }LgListView<TItem>Proposed page sizes; the value 0 proposes "All".
SelectableRowsboolfalseLgListView<TItem>Activates selection (checkbox before each item).
SelectionICollection<TItem>nullLgListView<TItem>Mutable collection of selected items; created by the component if omitted.
ShowFiltersboolfalseLgListView<TItem>Filter panel visibility, bindable in two-way via ShowFiltersChanged; hiding the panel preserves filter values.
ShowFiltersSummaryboolfalseLgListView<TItem>Summarizes active filters under the title ("Label: value", at most two then "+N"), like the grid, when the filter panel is hidden.
SortOptionsRenderFragmentnullLgListView<TItem>Declarations of sortable fields (LgListViewSort components); the initial sort is the one marked IsDefault="true", none otherwise.
StateIdstringnullLgListView<TItem>State persistence identifier (sort, page size, filters, panel, collapsed groups) in browser local storage.
StripeContentRenderFragment<TItem>nullLgListView<TItem>Content rendered in the color stripe of the default card (and of RenderStripe() in ItemTemplate); gives a stripe to all items.
StripeCssClassSelectorFunc<TItem, string>nullLgListView<TItem>CSS classes of the card stripe (theme color for example); the stripe is rendered when this selector, ColorSelector, or StripeIconSelector returns a value, or with StripeContent.
StripeIconSelectorFunc<TItem, string>nullLgListView<TItem>Name of the icon displayed in the card stripe; an icon alone renders the stripe, in theme color.
TitlestringnullLgListView<TItem>Title displayed in the frame header; {0} (total item count) and {1} (page items) are replaced by counters from the last load, ... while unknown.
TitleContentRenderFragmentnullLgListView<TItem>Free content rendered after the title in the header.
ToolbarRenderFragmentnullLgListView<TItem>Buttons added to the action bar of the header, before built-in buttons (filters, sort).
ToolbarSelectionRenderFragmentnullLgListView<TItem>Content added to the action panel displayed when at least one item is selected.
TooltipIsHtmlboolfalseLgListView<TItem>Interprets tooltips from TooltipSelector in HTML format.
TooltipSelectorFunc<TItem, string>nullLgListView<TItem>Tooltip of an item's card.
VirtualizeboolfalseLgListView<TItem>Renders only visible items (those of the current page with AllowPaging).
VirtualizeItemSizefloat50LgListView<TItem>Expected height of an item (in pixels) in virtualized rendering.
AriaLabelstringnullLgAriaComponentBaseTranslated ARIA label of the root group.
AriaLabelledBystringnullLgAriaComponentBaseIdentifier of the element that names the root group.

LgListViewSort<TItem>​

Declaration of a sortable field in the SortOptions section. This component is never rendered: its declarations are read by the list. TItem is inferred from the enclosing LgListView.

NameTypeDefaultDeclared inDescription
IsDefaultboolfalseLgListViewSort<TItem>Makes this field the initial sort; without a default declaration, the list is not sorted initially.
KeystringnullLgListViewSort<TItem>Sort key (persisted state, Key of OnSortChanged); defaults to the member path of SortSelector, required for a computed expression.
SortSelectorExpression<Func<TItem, object>>nullLgListViewSort<TItem>Sort key per item x => x.Member (required). A computed expression only works locally.
TextstringnullLgListViewSort<TItem>Label displayed in the sort menu; defaults to the Name of [Display] of the member, then the key.

LgListViewFilter<TItem, TValue>​

Filter of the Filters panel, rendered with the filter box of LgGridView corresponding to TValue. TItem is inferred from the enclosing LgListView and TValue from FilterSelector.

NameTypeDefaultDeclared inDescription
FilterSelectorExpression<Func<TItem, TValue>>nullLgListViewFilter<TItem, TValue>Filtered value x => x.Member (required); its type chooses the filter box. Frozen at initialization.
ItemsIEnumerable<TValue>nullLgListViewFilter<TItem, TValue>Values offered by the "Selection" tab; if absent, values from the source filtered by the other filters.
KeystringnullLgListViewFilter<TItem, TValue>Filter key (persisted state, keys of OnFilterChanged); defaults to the member path of FilterSelector, required for a computed expression.
TextstringnullLgListViewFilter<TItem, TValue>Filter label (panel and filter summary); defaults to the Name of [Display] of the member, then the key.
Cascading parameters

LgListViewFilter receives the enclosing LgListView in cascade: it can only be used in the Filters section of an LgListView (an exception is raised otherwise).

Methods & events​

Public methods invocable via @ref:

MethodDescription
RefreshAsync()Reloads data from source (local or remote). Only a remote load displays the loading indicator: local items are updated in place (focus is preserved).
ClearFiltersAsync()Empties all filters then reloads data; has no effect when no filter is active.
ExpandAllGroups()Expands all groups (with GroupSelector), like the "Expand all groups" button; persisted with StateId.
CollapseAllGroups()Collapses all groups (with GroupSelector), like the "Collapse all groups" button; persisted with StateId.

Events:

EventArgument typeDescription
ActiveItemChangedTItemActive item (two-way binding of ActiveItem), triggered on card click or by ActivateAsync().
CollapsedChangedboolThe list was collapsed or expanded by clicking the header (two-way binding of Collapsed).
CurrentPageChangedintCurrent page (two-way binding of CurrentPage).
ListViewDataCounterChangedListViewDataCounterCounters updated after each load (two-way binding of ListViewDataCounter).
OnFilterChangedListViewFilterChangedEventArgsSet of active filters changed, including on restore from StateId (Filters indexed by filter key, HasFilters()).
OnItemClickTItemClick on an item's card (after confirmation and active item change); makes cards clickable.
OnItemDropListViewDropEventArgs<TItem>An item is released on an accepted position of this list (target list), before item update: Cancel refuses the drop, Handled indicates the handler updated items. Required for group change.
OnItemDroppedListViewDropEventArgs<TItem>Dropped item is in place (items updated, lists reloaded), on the target list.
OnRowSelectionListViewSelectionEventArgs<TItem>Selection changed (Selection, SelectedItem, SelectAction).
OnSortChangedListViewSortEventArgsSort changed (Key: sort key, SortDirection — see DataSortDirection; Sorts: same sort as GridViewSortEventArgs.Sorts, 0 or 1 item).
ShowFiltersChangedboolFilter panel visibility (two-way binding of ShowFilters).

Associated enumerations​

ListViewFiltersPosition​

Position of the filter panel, carried by FiltersPosition (default: Top).

ValueDescription
TopPanel above items, in the list.
PopupCentered modal window, over the page.
LeftFull-height drawer sliding from the left edge of the screen.
RightFull-height drawer sliding from the right edge of the screen.

ListViewDragMode​

Drag-and-drop capabilities, carried by DragMode (combinable flags, default: None).

ValueDescription
NoneNo drag-and-drop.
ReorderItems can be moved in the list; has no effect when the list is sorted.
DragOutItems can be dragged to another list of the same DragGroup.
DropInList accepts items dragged from another list of the same DragGroup.
CopyItems dragged to another list are copied: list keeps them (with DragOut).
AllReorder, DragOut, and DropIn.

ListViewSelectAction​

Type of selection change, carried by ListViewSelectionEventArgs<TItem>.SelectAction.

ValueDescription
SelectItemSelection of an item.
UnselectItemDeselection of an item.
SelectAllSelection of all loaded items.
UnselectAllDeselection of all items.
SelectGroupSelection of displayed items of a group (group header checkbox).
UnselectGroupDeselection of displayed items of a group (group header checkbox).

Best practices / accessibility​

  • LgListView renders a role="group" frame containing a role="list" area and role="listitem" elements. AriaLabel and AriaLabelledBy name this group (the title keeps its own text): set them when the visual title is not enough.
  • Each selection checkbox is named by the content of its item (aria-labelledby): take care with the text of ItemTemplate, that's what a screen reader announces. The "Select all" checkbox is named by the action it triggers ("Select all" / "Deselect all").
  • Do not place the list in an LgFrame: it is already a frame.
  • In remote or paginated mode, selection needs a key: set KeyField, unless in remote mode the Id property of the model identifies the item (default key). Without a key, reloaded instances are no longer equal to selected instances.
  • For large remote data, combine Virtualize with AllowPaging: without pagination, virtualization loads the entire source.
  • In ItemTemplate, like with ColorSelector / StripeContent, avoid conveying information only by color or icon: repeat it in text in the card body.
  • Clickable cards are focusable and activable by keyboard; the group header has an aria-expanded button for collapse, and its checkbox an aria-checked="mixed" state when the group is partially selected. With GroupSelector, the items area of each group is a role="list" named by the group key.
  • Don't convey active state or group status only by color (ColorSelector, GroupColorSelector): repeat it in text.
  • With DragMode, the handle is a button named "Move item" and described by keyboard instructions; keyboard movement is announced by an aria-live region. Also offer an action without dragging (button, menu) when an item must change lists: keyboard only reorders in its list.
Complete reference

Consult the API Reference — LgListView for the generated list of public members.

  • LgGridView for data tables in columns, inline editing, multi-level grouping, and export.
  • LgFrame, the frame in which the list is rendered (header, collapse, Kind).
  • LgToolbar and LgToolbarButton to compose header or selection actions.
  • LgCard to structure the content of each item.