Skip to content
IzzyBlazor 0.1.0-alpha.20

Enter all results ↑ ↓ move Esc close

DataGrid

Since 0.1.0-alpha.20
Edit, group, filter by row and arrange columns, with state in the URL.

Static server-side rendering: no circuit, no WebAssembly.

A data grid with editing, grouping, filters and columns people arrange, its state in the address so it works on static pages too. Cells take arrow keys, a row can open a detail, columns hide to fit a phone, and it exports to CSV and Excel.

Usage

razor
<DataGrid Items="orders" ItemKey="o => o.Id" PageSize="20" Caption="Orders">
    <PropertyColumn Property="o => o.Id" Title="Order" Width="8.Rem" Frozen="ColumnFrozen.Start" />
    <PropertyColumn Property="o => o.Customer" Sortable Filterable MinWidth="12.Rem" />
    <PropertyColumn Property="o => o.Total" Format="C" Sortable Width="10.Rem" />
</DataGrid>

Topics

  • Columns: Let people resize, move, hide and freeze columns.
  • Filtering: A filter on each column, a row of filters, one of your own, and a builder for what they can't hold.
  • Aggregates: Totals over every row the filters match, in the footer.
  • Grouping: Group by columns, a page of groups at a time, with values for each group.
  • Master-detail: Open a row's detail under it, such as its lines in a grid of their own.
  • Adaptability: Fit phones and narrow spaces: hide columns that don't fit, and show their values under the row.
  • Editing: Edit in a dialog, in the row, or a cell at a time.
  • Export: Download what's on screen as Excel or CSV.

Columns

Give a column a Width to keep it, and the others share the rest down to their MinWidth, when the grid scrolls sideways. Shift+click a header to add it to the sort.

Preview

Orders
SelectOrder
Customer
Date Status Total
1007Ada LovelaceOct 20Pending$316.75
1014Ada LovelaceOct 19Refunded$149.00
1021Ada LovelaceOct 18Failed$441.25
1006Alan TuringOct 13Refunded$275.00
1013Alan TuringOct 12Failed$107.25

Code

Columns.razor
@* Order, Date and Total keep their widths; Customer and Status share the rest, and past their
   minimums the grid scrolls sideways. Shift+click a header to add it to the sort. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
<DataGrid Items="Rows.All" ItemKey="o => o.Number.ToString()" PageSize="5" PageSizeOptions="[5, 10]" InitialSort="-date" Caption="Orders" SelectionMode="SelectionMode.Multiple" Grow>
    <PropertyColumn Property="o => o.Number" Title="Order" Align="CellAlign.Start" Width="6.Rem" />
    <PropertyColumn Property="o => o.Customer" Sortable Filterable MinWidth="12.Rem" />
    <PropertyColumn Property="o => o.Date" Format="MMM d" Sortable Width="8.Rem" />
    <TemplateColumn Title="Status" SortBy="o => o.Status" SortKey="status" Sortable>
        <Badge Status="Rows.StatusOf(context.Status)" Dot>@context.Status</Badge>
    </TemplateColumn>
    <PropertyColumn Property="o => o.Total" Format="C" Sortable Width="8.Rem" />
</DataGrid>

Row appearance

Striped alternates the rows' backgrounds, ColumnLines adds a line between columns, ShadedHeader shades the header, and RowLines set to false takes away the line between rows. RowHover highlights the row under the pointer, to help follow a wide one across. It's off by default, as a highlight suggests a row does something: a row with a RowHref always has it.

Preview

Orders with stripes and lines
OrderCustomerDateTotal
1001Margaret Hamilton9/8/2026$66.25
1002Katherine Johnson9/15/2026$108.00
1003Grace Hopper9/22/2026$149.75
1004Barbara Liskov9/29/2026$191.50
1005Linus Torvalds10/6/2026$233.25

Code

Appearance.razor
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
@* Stripes, a line between columns, and a highlight under the pointer. Lines between rows are on unless
   RowLines is false. *@
<DataGrid Items="Rows.All" PageSize="5" Caption="Orders with stripes and lines" Striped ColumnLines RowHover Grow>
    <PropertyColumn Property="o => o.Number" Title="Order" Align="CellAlign.Start" Width="6.Rem" />
    <PropertyColumn Property="o => o.Customer" />
    <PropertyColumn Property="o => o.Date" Format="d" />
    <PropertyColumn Property="o => o.Total" Format="C" Width="9.Rem" />
</DataGrid>

ToolbarContent puts your own ToolbarButtons above the grid, and Searchable adds a search box across the text columns, with the words in the address. While rows are selected, the bar of SelectionActions takes the toolbar's place, and SelectAllMode says what the header checkbox takes: the page, or every row the filters match.

Preview

Orders with tools
SelectOrderCustomer Date Total
1001Margaret HamiltonSep 8$66.25
1002Katherine JohnsonSep 15$108.00
1003Grace HopperSep 22$149.75
1004Barbara LiskovSep 29$191.50
1005Linus TorvaldsOct 6$233.25

Code

Toolbar.razor
@* Your own buttons above the grid, and a search box whose words are in the address. Select a row and
   the bar of SelectionActions takes the toolbar's place, so the rows stay where they are. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
<DataGrid Items="Rows.All" ItemKey="o => o.Number.ToString()" PageSize="5" Caption="Orders with tools" SelectionMode="SelectionMode.Multiple" SelectAllMode="SelectAllMode.All" Searchable QueryPrefix="tools-" SelectionName="tools" Grow>
    <ToolbarContent>
        <ToolbarButton StartIcon="Lucide.Plus" Position="ToolbarPosition.End" Variant="ButtonVariant.Outline">New order</ToolbarButton>
        <ToolbarButton StartIcon="Lucide.Download" Position="ToolbarPosition.End">Export</ToolbarButton>
    </ToolbarContent>
    <SelectionActions>
        <Button Size="ControlSize.Sm" Variant="ButtonVariant.Outline" Accent="Accent.Neutral" StartIcon="Lucide.Archive">Archive</Button>
    </SelectionActions>
    <ChildContent>
        <PropertyColumn Property="o => o.Number" Title="Order" Align="CellAlign.Start" Width="6.Rem" />
        <PropertyColumn Property="o => o.Customer" Sortable />
        <PropertyColumn Property="o => o.Date" Format="MMM d" Sortable Width="8.Rem" />
        <PropertyColumn Property="o => o.Total" Format="C" Sortable Width="8.Rem" />
    </ChildContent>
</DataGrid>

Row menus

An ActionColumn with Overflow set to RowActionOverflow.Always gives each row a ⋮ menu of RowActions, and with script a right-click, a long press, Shift+F10 or the menu key open the same menu. It acts on the row it opened on, whatever is selected. A right-click on a link keeps the browser's menu.

Preview

Orders with menus
OrderCustomerTotalActions
1001Margaret Hamilton$66.25
1002Katherine Johnson$108.00
1003Grace Hopper$149.75
1004Barbara Liskov$191.50
1005Linus Torvalds$233.25

Code

RowMenu.razor
@* Right-click a row, press and hold it on a phone, or press Shift+F10 on a cell: the same menu as its
   ⋮ button, which works with no script. A paid order has no Cancel. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
@inject NavigationManager Navigation
<DataGrid Items="Rows.All" PageSize="5" Caption="Orders with menus" ItemKey="o => o.Number.ToString()" QueryPrefix="menus-" Grow>
    <PropertyColumn Property="o => o.Number" Title="Order" Align="CellAlign.Start" Width="6.Rem" />
    <PropertyColumn Property="o => o.Customer" />
    <PropertyColumn Property="o => o.Total" Format="C" Width="8.Rem" />
    <ActionColumn Context="order" Overflow="RowActionOverflow.Always">
        <RowAction Label="@($"View {order.Number}")" Href="@Navigation.GetUriWithQueryParameter("order", order.Number)" />
        <RowAction Label="@($"Cancel {order.Number}")" Href="@Navigation.GetUriWithQueryParameter("cancel", order.Number)" Visible="order.Status != Table.OrderStatus.Paid" />
    </ActionColumn>
</DataGrid>

Controls in cells

Tab moves into the grid once, and arrow keys move between its cells. A cell with one button or link focuses it directly, so Enter uses it. In a cell with several controls or a field, press Enter to go in and Escape to come back.

Preview

Orders to review
OrderCustomer NotePriorityActionsMore
1001Margaret Hamilton
1002Katherine Johnson
1003Grace Hopper
1004Barbara Liskov
1005Linus Torvalds
1006Alan Turing
1007Ada Lovelace
1008Margaret Hamilton
1009Katherine Johnson
1010Grace Hopper
1011Barbara Liskov
1012Linus Torvalds
1013Alan Turing
1014Ada Lovelace
1015Margaret Hamilton
1016Katherine Johnson
1017Grace Hopper
1018Barbara Liskov
1019Linus Torvalds
1020Alan Turing
1021Ada Lovelace
1022Margaret Hamilton
1023Katherine Johnson

Code

Cells.razor
@* Cells that hold controls, small to keep the rows' height. One button or menu takes focus directly;
   with several, or a field that uses the arrows itself, Enter goes in and Escape comes back. The
   header stays in view when the rows scroll. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
<DataGrid Items="Rows.All" ItemKey="o => o.Number.ToString()" MaxHeight="16.Rem" Caption="Orders to review" Grow>
    <PropertyColumn Property="o => o.Number" Title="Order" Align="CellAlign.Start" Width="6.Rem" />
    <PropertyColumn Property="o => o.Customer" Sortable Width="12.Rem" />
    <TemplateColumn Title="Note" Context="order">
        @{ var review = _reviews[order.Number]; }
        <TextField @bind-Value="review.Note" Label="@($"Note for order {order.Number}")" HideLabel Size="ControlSize.Sm" />
    </TemplateColumn>
    <TemplateColumn Title="Priority" Width="8.Rem" Context="order">
        @{ var review = _reviews[order.Number]; }
        <Select @bind-Value="review.Priority" Items="Priorities" Label="@($"Priority of order {order.Number}")" HideLabel Size="ControlSize.Sm" />
    </TemplateColumn>
    <TemplateColumn Title="Actions" Width="10.Rem" Context="order">
        <Row Gap="1">
            <Button Size="ControlSize.Sm" Variant="ButtonVariant.Outline" Accent="Accent.Neutral">Open</Button>
            <Button Size="ControlSize.Sm" Variant="ButtonVariant.Ghost" Accent="Accent.Neutral">Copy</Button>
        </Row>
    </TemplateColumn>
    <TemplateColumn Title="More" Width="4.Rem" Context="order">
        <Menu>
            <Trigger Context="wire">
                <IconButton Icon="Lucide.Ellipsis" Label="@($"Actions for order {order.Number}")" Variant="ButtonVariant.Ghost" Accent="Accent.Neutral" Size="ControlSize.Sm" @attributes="wire" />
            </Trigger>
            <ChildContent>
                <MenuItem>Archive</MenuItem>
            </ChildContent>
        </Menu>
    </TemplateColumn>
</DataGrid>

@code {
    private static readonly string?[] Priorities = ["Normal", "High", "Low"];

    // Each order's own note and priority, not one shared by every row.
    private readonly Dictionary<int, Review> _reviews = Rows.All.ToDictionary(o => o.Number, o => new Review { Priority = o.Number % 4 == 1 ? "High" : "Normal" });

    private sealed class Review
    {
        public string? Note { get; set; }

        public string? Priority { get; set; }
    }
}

Virtual rows

Virtualize draws only the rows in view, on an interactive page, so 100,000 rows scroll as easily as 100. Give it a MaxHeight, and keep rows to one line of RowHeight. On a static page, as here unless you switch this page to Interactive, the same grid loads more rows on scroll instead.

Preview

Every order
SelectNumber CustomerTotal
1Katherine Johnson$108.00
2Grace Hopper$149.75
3Barbara Liskov$191.50
4Linus Torvalds$233.25
5Alan Turing$275.00
6Ada Lovelace$316.75
7Margaret Hamilton$358.50
8Katherine Johnson$400.25
9Grace Hopper$442.00
10Barbara Liskov$483.75
11Linus Torvalds$65.50
12Alan Turing$107.25
13Ada Lovelace$149.00
14Margaret Hamilton$190.75
15Katherine Johnson$232.50
16Grace Hopper$274.25
17Barbara Liskov$316.00
18Linus Torvalds$357.75
19Alan Turing$399.50
20Ada Lovelace$441.25
1–20 of 100,000

Code

VirtualRows.razor
@* 100,000 rows, of which only those in view are drawn, each window read as a database would be. Switch
   this page to Interactive to see it; a static page loads more on scroll instead. *@
@using IzzyBlazor.Site.Examples.Table
<DataGrid TItem="Order" ItemsProvider="LoadAsync" ItemKey="o => o.Number.ToString()" Caption="Every order" Virtualize RowHeight="40" MaxHeight="24.Rem" PageSize="20" SelectionMode="SelectionMode.Multiple" SelectionName="every" QueryPrefix="every-" Grow>
    <PropertyColumn Property="o => o.Number" Sortable Align="CellAlign.Start" Width="8.Rem" />
    <PropertyColumn Property="o => o.Customer" />
    <PropertyColumn Property="o => o.Total" Format="C" Width="8.Rem" />
</DataGrid>

@code {
    private static readonly IReadOnlyList<Order> Many = Enumerable.Range(1, 100_000)
        .Select(i => Orders.All[i % Orders.All.Count] with { Number = i })
        .ToList();

    private async ValueTask<DataResult<Order>> LoadAsync(DataRequest<Order> request)
    {
        // As long as a query takes, so you can see rows on their way.
        if (RendererInfo.IsInteractive)
        {
            await Task.Delay(150, request.CancellationToken);
        }

        return request.ToResult(Many.AsQueryable());
    }
}

Placing the toolbar's tools

Write DataGridSearch, DataGridExport or DataGridColumnPicker in ToolbarContent to place the grid's own tools among yours, in the order written; one you don't write keeps its usual place, and the grid's parameter still turns it on. Write them directly in ToolbarContent, not inside a component of your own. Export and Columns show only their icons with a hover tooltip, as suits a grid used all day: ToolbarLabels adds text to both, and ShowText to one.

Preview

Orders with placed tools
NumberCustomer Total
1001Margaret Hamilton$66.25
1002Katherine Johnson$108.00
1003Grace Hopper$149.75
1004Barbara Liskov$191.50
1005Linus Torvalds$233.25

Code

ToolbarOrder.razor
@* The grid's own tools among yours, in the order written. Export has its text; the others are as usual. *@
@using Rows = IzzyBlazor.Site.Examples.Table.Orders
<DataGrid Items="Rows.All" PageSize="5" Caption="Orders with placed tools" Searchable ColumnPicker LayoutKey="order-tools" QueryPrefix="placed-" ExportCsvHref="/examples/orders.csv" ExportExcelHref="/examples/orders.xlsx" Grow>
    <ToolbarContent>
        <ToolbarButton StartIcon="Lucide.Plus" Variant="ButtonVariant.Outline" Priority="1">Add order</ToolbarButton>
        <DataGridSearch />
        <DataGridColumnPicker Position="ToolbarPosition.End" />
        <ToolbarIconButton Icon="Lucide.CircleQuestionMark" Label="Help" Position="ToolbarPosition.End" />
        <DataGridExport Position="ToolbarPosition.End" ShowText />
    </ToolbarContent>
    <ChildContent>
        <PropertyColumn Property="o => o.Number" Align="CellAlign.Start" Width="8.Rem" />
        <PropertyColumn Property="o => o.Customer" Sortable />
        <PropertyColumn Property="o => o.Total" Format="C" Sortable Width="8.Rem" />
    </ChildContent>
</DataGrid>

Details

Groupable lets people group by columns from a header's menu, and InitialGroup or Group starts grouped. The grouping and what's open are in the address (?group=status&open=Shipped), so a group's row is a link and this works with no script. A page counts top-level groups, a group is never split, and whatever Paging or Virtualize say, a grouped grid draws numbered pages. Aggregate on a column works out a value over every row the filters match, for the footer and each group's row. With an ItemsProvider, either one needs a GroupsProvider: rows still come from your provider, with the group's values in the filter.

LayoutKey remembers how one person has arranged the columns (widths, order, hidden, frozen) in a cookie, so the server draws it on the first paint with no flash. It's per person and per page; a shared link still shows the same rows, since sort, filter and page are in the address. To keep layouts in a database instead, bind Layout.

ResizableColumns, ReorderableColumns and ColumnPicker let people rearrange the columns, with script, by pointer, keys, a menu in each header and a picker above the grid. On a static page they need somewhere to keep the result: a LayoutKey, or Layout with a LayoutSaveUrl.

A toolbar above the grid holds ToolbarContent (Toolbar's items), the search box with Searchable, export and the Columns button, which show their icons alone unless ToolbarLabels is set. Write DataGridSearch, DataGridExport or DataGridColumnPicker in ToolbarContent to place one among your items. While rows are selected, the bar of SelectionActions takes its place. Searchable searches the text columns; the words go in the address (?search=), and with script apply as you type.

Virtualize draws only the rows in view, for tens of thousands of them, on an interactive page: give it a MaxHeight, and keep rows to one line of RowHeight. An ItemsProvider gets each window as a Skip and Take, and returns the Total. On a static page it loads on scroll instead, by PageSize (50 if not set), up to 2,000 rows. If the focused row scrolls away, focus waits on the scroll box and goes back when it returns, or on the next key, which scrolls to it. Browser find, and Shift ranges of selection, reach the rows drawn, unless SelectAllMode is All.

ExportExcelHref, and ExportCsvHref beside it if CSV is wanted too, add plain links to endpoints the app maps with DataExport. With both, one button with a chevron opens a menu of them. They carry the filter, sort, search and visible columns, in every mode and with no script. The endpoint's fields decide what's written, and head the file. A download matches the screen when they have the grid's keys: a column whose key they don't have is left out, a filter on it matches nothing, and a sort on it is ignored. Search covers their searchable fields, which may not be the grid's text columns. Text doesn't carry FilterCase, so a grid that sets it needs the same Case on those fields.

ActionColumn holds a row's actions in a last column: EditAction, DeleteAction and your own RowActions, each a button, or with Overflow="RowActionOverflow.Always" in a ⋮ menu, which works with no script. In a grid that hides columns, buttons move into the menu once one is hidden, unless they say Never. A grid with editing has one by itself. With script a right-click on the row, a long press, Shift+F10 or the menu key opens the row's menu. It acts on the row it opened on, and doesn't change the selection; actions on the selection go in the bar. A right-click on a link keeps the browser's menu, with its "open in new tab": that includes the whole of a row with RowHref, whose ⋮ button and Shift+F10 still open the menu.

EditMode with OnSave edits a row, with no script needed. Each column gets a field chosen by its type (a text area for text with [DataType(DataType.MultilineText)]) if it can be edited, shown or not: set Editable="false" on what can't be, such as the key, which a save can't change. Visible="false" starts a column hidden, for a field the table doesn't show, or for people to show from the picker. Each row has an Edit link, which puts its key in the address (?edit=42), and a save is a form post. Only editable columns take a value from it, so a forged field changes nothing. OnSave gets a copy of the row, and either finishes, which closes the editor and loads the rows again, or adds errors, which stay on the fields. A grid with editing can't be inside another form, as forms can't nest. It needs an ItemKey, and on a static page, a row type Blazor can fill from a form: public settable properties.

razor
<DataGrid Items="orders" ItemKey="o => o.Id.ToString()" EditMode="DataGridEditMode.Dialog" OnSave="SaveAsync">
    <PropertyColumn Property="o => o.Id" Editable="false" />
    <PropertyColumn Property="o => o.Customer" />
    <PropertyColumn Property="o => o.Notes" Visible="false" />
</DataGrid>

DataGridEditMode.Row edits where the row stands, with Save and Cancel in place of its actions, also with no script. Only the columns shown have a field, so a hidden one keeps its value. A new row starts at the top of the page. Sorting, filtering or changing page ends the edit, and what's typed goes with it. It can't be used with Virtualize or loading on scroll, or with an EditFormTemplate.

DataGridEditMode.Cell edits one cell at a time on an interactive page, and OnSave runs for each one that changed. A click, Enter, F2 or typing starts it; Tab, Enter or a click elsewhere saves it, and an invalid cell stays open. A new row is edited as with Row, and so is every row on a static page. Besides the limits of Row, it can't be used with RowHref.

Parts

Written inside DataGrid. The API page lists their parameters.

  • ActionColumn<TItem>: the column that holds a row's actions, at the end of a DataGrid.
  • RowAction: an action of your own on a row: an icon button with a tooltip, or an item in its menu.
  • EditAction: the row's edit action: a pencil, or an item in its menu.
  • DeleteAction: the row's delete action, which asks first: a trash can, or an item in its menu.
  • EditLayout<TItem>: sets up a DataGrid's generated edit dialog.
  • EditField: a column's generated field, placed in an EditLayout<T>.
  • EditFormTemplate<TItem>: your own form in a DataGrid's edit dialog, in place of the generated one, for what isn't fields of the row, such as steps or a save across several records.
  • DataGridAdd: puts a DataGrid's Add button, from NewItem, among your toolbar items.
  • DataGridSearch: puts a DataGrid's search box, from Searchable, among your toolbar items.
  • DataGridExport: puts a DataGrid's export, from ExportExcelHref and ExportCsvHref, among your toolbar items: a link with one of them, or with both a button with a chevron that opens a menu of links.
  • DataGridFilterBuilder: puts a DataGrid's Filter builder button, from FilterBuilder, among your toolbar items.
  • DataGridColumnPicker: puts a DataGrid's Columns button, from ColumnPicker, among your toolbar items.

Mode support

What works in each mode, DataGrid
FeatureStaticInteractive
Sort, filter and page through the URLYesYes
Column widths and sideways scrolling, set by the serverYesYes
Frozen columnsYesYes
Groups from all the data, a page of them, each opened by a linkYesYes
Aggregates over everything the filters match, in the footer and on groupsYesYes
Virtual rows on interactive pages, loading on scroll on static onesYesYes
A toolbar with search in the address, its tools placed among yoursYesYes
CSV and Excel export, streamed from an endpoint you mapYesYes
Editing a row in a dialog, saved by a form postYesYes
Row menus (right-click, long press and keys open them too)YesYes
Resizing, moving and hiding columns, kept per personYesYes
Selected rows post with a formYesYes
Shift+click sorts by several columnsYesYes
One Tab stop and arrow keys between cells, with selection keysYesYes

Static: static server-side rendering, with no circuit and no WebAssembly. Interactive: Server, WebAssembly or Auto.

Without JavaScript

Every page starts as plain HTML: before IzzyBlazor's script loads on a static page, while an interactive page prerenders, and with JavaScript off. With JavaScript off, there's no select-all checkbox and Shift+click doesn't add to the sort; filters apply when you press Apply; with columns hidden to fit, a row being edited shows their values in its detail, not fields.

Accessibility

  • Caption names the grid for screen readers; it isn't shown.
  • With script it's an ARIA grid, one Tab stop, with the keys below. A cell with one link, button or checkbox focuses that directly. With no script, it's a plain table and Tab goes through its controls.
  • Resizing and moving a column need no dragging: a header's keys and menu do both, and a new width is read out.
  • Sortable headers are links, and the first sorted column has aria-sort. With several sorted, each says its place and direction ("Sort 2, descending").
  • Row checkboxes and filter buttons are named as in a Table.
  • The toolbar is one Tab stop with script, with arrow keys between its controls. The tools that show only an icon are named for what they do, and have that as a hover tooltip.

Keyboard navigation

In the rows

DataGrid keys, In the rows
Press this keyTo do this
TabMove into the grid, and on past it
Up or DownMove to the row above or below
Left or RightMove to the cell before or after
Home or EndMove to the first or last cell of the row
Ctrl+Home or Ctrl+EndMove to the first cell of the first row, or the last cell of the last
PageUp or PageDownMove by the rows in view; from the edge of a page, to the next page
Enter or F2Go into a cell with several controls or a field
F2Edit the row, from a cell of text, in a grid that edits rows
EnterOn a row that's a link, follow it, from a cell of text
Alt+DownOpen the cell's menu
Shift+F10 or MenuOpen the row's menu (on a link, only Shift+F10)

Inside a cell

DataGrid keys, Inside a cell
Press this keyTo do this
TabMove among its controls, and back out past either end
Up or Down or Left or RightOn a button or link, move on to another cell; a field keeps them
Escape or F2Go back to the cell

Groups and details

DataGrid keys, Groups and details
Press this keyTo do this
Right or LeftOn a group's row, open or close it
EnterOn a group's row, or a row's detail button, open or close it
DownFrom a row, move to its open detail, one stop whatever it holds
Enter or F2Go into the detail
EscapeGo back to the detail from inside it, a grid in it too
TabInside the detail, move among its controls; from a grid in it, on past this grid

In a row being edited

DataGrid keys, In a row being edited
Press this keyTo do this
Tab or Shift+TabMove through its fields, then Save and Cancel
EnterIn a field, save
EscapeCancel, once any open list or picker has closed

With DataGridEditMode.Cell, on an interactive page

DataGrid keys, With DataGridEditMode.Cell, on an interactive page
Press this keyTo do this
Enter or F2 or typingEdit the cell, from a cell that can be edited
Tab or Shift+TabSave it, and edit the next or the one before
EnterSave it, and go back to the cell
EscapeCancel, and go back to the cell

Selecting rows

DataGrid keys, Selecting rows
Press this keyTo do this
SpaceSelect or clear the row, from a cell of text
Shift+SpaceSelect or clear the row, from anywhere in it but a field
Shift+Up or Shift+DownExtend the selection, or shrink it going back
Ctrl+ASelect what's on the page, or the rows drawn when they're virtual; every match with SelectAllMode.All

On a header

DataGrid keys, On a header
Press this keyTo do this
EnterSort by the column, if it sorts
Shift+EnterAdd the column to the sort; again, reverse it, then take it out
Alt+DownOpen its menu, or its filter when there's no menu
F2Go in to its controls, the sort link first
Shift+F10 or MenuOpen its menu
Shift+Left or Shift+RightResize the column, where it can be
Alt+Left or Alt+RightMove the column, where it can be
PageDownGo to the first row

In the footer

DataGrid keys, In the footer
Press this keyTo do this
TabMove through the page size button and the pager's links
EnterFollow the link

In the filter row

DataGrid keys, In the filter row
Press this keyTo do this
Up or DownMove to the header above or the row below
Left or RightMove to the filter before or after
Enter or F2Go into the filter's field
Alt+DownOpen the column's filter panel

Inside a filter cell

DataGrid keys, Inside a filter cell
Press this keyTo do this
Tab or Shift+TabMove between the field and the filter button, and back out past either end
EnterIn the field, filter now without waiting
Alt+DownIn the field, open the column's filter panel
Escape or F2Go back to the cell; the filter stays

In a filter panel

DataGrid keys, In a filter panel
Press this keyTo do this
Tab or Shift+TabMove among the operator, the values and the list
EnterFilter now and close, from a field or the list's search box
EscapeClose and go back to the filter button; the filter stays

In a filter's list

DataGrid keys, In a filter's list
Press this keyTo do this
DownMove from the search box to the first value
Up or DownMove among the values; Up from the first goes to the search box
Home or EndMove to the first or last value
SpaceTick or untick the value

Parameters

DataGrid parameters
PropTypeDefault
DetailTemplateA row's detail: drawn under it, across the grid, while it's open.RenderFragment<TItem>?
ItemHasDetailWhich rows have a detail; all of them when it's not set.Func<TItem, bool>?
@bind-OpenDetailsWhich rows' details are open, by key; "*" is all of them, and "!key" an exception to that.IReadOnlyList<string>?
DetailsOpenWhether every row's detail starts open.boolfalse
SingleDetailOpening a row's detail closes the one that was open.boolfalse
GroupableLets people group by columns, from a header's menu.boolfalse
@bind-GroupThe grouping, outermost first, such as "status,-customer" (- for descending); null for InitialGroup.string?
InitialGroupThe grouping when the URL has none, such as "status".string?
GroupsOpenWhether groups start open.boolfalse
@bind-OpenGroupsWhich groups are open, each by its values joined with /, escaped, such as "Shipped/Acme"; "*" is all of them, and "!Shipped" an exception to that.IReadOnlyList<string>?
GroupRowLimitThe most rows drawn in one open group.int100
GroupPanelKeeps the bar of what's grouped above the grid while nothing is, saying a header can be dragged there.boolfalse
ShowGroupedColumnsKeeps a grouped column in the table.boolfalse
SmallScreenWhat it does when its columns don't fit its width: DataGridSmallScreen.Scroll (the default) scrolls sideways; DataGridSmallScreen.HideColumns hides columns by their Priority and shows their values in the row's detail.DataGridSmallScreenDataGridSmallScreen.Scroll
NonceA CSP nonce for the style element that holds the widths where columns hide.string?computed
EditModeHow a row is edited.DataGridEditModeDataGridEditMode.None
FindItemFinds a row that isn't among those loaded, by its key, for the edit dialog and the delete confirmation: a link to a row on another page, say.Func<string, Task<TItem>>?
NewItemA new row's starting values.Func<TItem>?
ItemEditableWhich rows can be edited; all of them when it's not set.Func<TItem, bool>?
ItemDeletableWhich rows can be deleted; all of them when it's not set.Func<TItem, bool>?
@bind-EditKeyThe key of the row being edited, or null.string?
EditCopyMakes the copy of a row that's edited, on an interactive page, in place of a shallow copy: for a type that holds what a copy mustn't share.Func<TItem, TItem>?
LayoutKeyRemembers how each person has arranged the columns, in a cookie under this name, so the server draws it on the first paint.string?
@bind-LayoutHow the columns are arranged, in place of the cookie: bind it (@bind-Layout) to keep layouts yourself, such as per user in a database.DataGridLayout?
LayoutSaveUrlWith script, an address the app maps to save a person's layout: the grid posts it there as JSON when it changes, for a static page that passes its own Layout.string?
ResizableColumnsLets people resize columns: by dragging a handle at the header's end, by double-clicking it to fit, by Shift+Left and Shift+Right, or from the header's menu.boolfalse
ReorderableColumnsLets people move columns: by dragging a header, by Alt+Left and Alt+Right, or from the header's menu, which can also freeze them.boolfalse
ColumnPickerA button above the grid listing the columns to show or hide, and to put back as declared.boolfalse
VirtualizeDraws only the rows in view, on an interactive page; on a static page they load on scroll instead, by PageSize (50 if not set), up to 2,000 rows.boolfalse
RowHeightThe height of every row, in pixels, with Virtualize.double48
ToolbarLabelsText beside the icons of the toolbar's own tools, for a grid people use now and then.boolfalse
ExportCsvHrefA link in the toolbar, in a menu with ExportExcelHref, to an endpoint that writes the rows as CSV with DataExport, for a grid that offers CSV besides Excel.string?
ExportExcelHrefA link in the toolbar, in a menu with ExportCsvHref, to an endpoint that writes the rows as an Excel workbook with DataExport.string?
ToolbarContentThe page's own controls in the toolbar above the grid: ToolbarButton, ToolbarMenu and the like.RenderFragment?
SearchableA search box in the toolbar, across the text columns.boolfalse
@bind-SearchThe words searched for.string?
SearchLabelThe search box's name and placeholder.string?"Search"
FilterRowAdds a row of filters under the titles: a field for each column, then its filter button, which opens the column's panel, where the operator is chosen.boolfalse
FilterBuilderAdds a Filter builder button to the toolbar, for groups of conditions no column's filter can hold.boolfalse
GroupsProviderCounts and aggregates for an ItemsProvider, which a column's Aggregate needs.Func<DataGroupRequest<TItem>, ValueTask<DataGroupResult>>?
ChildContentThe columns: PropertyColumn<T1, T2> and TemplateColumn<T>.RenderFragment?
InitialSortThe sort when the URL has none, such as "name" or "-date" (descending).string?
@bind-SortThe sort, such as "name" or "-date" (descending), or several in a DataGrid ("status,-date"); null for InitialSort.string?
@bind-FilterThe filter: Filter.All of a condition per filtered column (contains for text, between for numbers, equals for dates, equals or in for choices), or null for none.Filter?
FilterCaseHow text compares in the column filters and search.FilterCaseFilterCase.IgnoreCase
FilterPanelA row below the rows that lists the active filters, each with a button to remove it, and Clear for all of them.boolfalse
CaptionThe table's name for screen readers (a visually hidden caption).string?
RowClassA class for each row, such as one that highlights overdue orders.Func<TItem, string?>?
RowHoverHighlights the row under the pointer, to help follow a wide one across.boolfalse
StripedAlternating row backgrounds.boolfalse
RowLinesA line between rows.booltrue
ColumnLinesA line between columns.boolfalse
ShadedHeaderShades the header, and a DataGrid's FilterRow with it, so they read apart from the rows; its color is --ib-table-head-bg.boolfalse
BorderedA rounded border around the table.booltrue
SizeRow height and text size.ControlSizeControlSize.Md
MaxHeightA height limit: the rows scroll and the header stays in view.Length?
RowHrefMakes each row a link, such as to the item's details page.Func<TItem, string?>?
RowCurrentThe row for what the page is showing, such as the one whose details are in a panel beside the table: drawn as selected, and marked aria-current (on its link with RowHref).Func<TItem, bool>?
RowLabelNames a row for screen readers, in its link and its checkbox.Func<TItem, string>?computed
FilterFromAddressApplies a whole filter from the address (?filter=, with the QueryPrefix), as a FilterBuilder<T> on the page writes it, along with the columns' own.boolfalse
ItemsThe items.IEnumerable<TItem>?
ItemsProviderLoads the items yourself, in place of Items: the request has the range (and in a Table the sort, the filter and the columns as fields), so request.ToResultAsync(query, ...) or request.Apply(query) does the work.Func<DataRequest<TItem>, ValueTask<DataResult<TItem>>>?
@bind-PageSizeItems per page.int?
PageSizeOptionsSizes to choose from in a "Rows per page" menu in the footer, such as new[] { 10, 25, 50 }.IReadOnlyList<int>?
@bind-PageThe page, from 1.int?
PagingHow it moves through its pages when it has a PageSize: numbered pages (DataPaging.Pages, the default, which needs a total), or by cursor, with no total needed: First, Previous and Next (DataPaging.NextPrevious), a "Load more" button after the items (DataPaging.LoadMore, ListView only), or loading as the last item comes into view (DataPaging.LoadOnScroll).DataPagingDataPaging.Pages
LoadMoreTextThe "Load more" button's text, such as "Load earlier".string?"Load more"
@bind-CursorThe cursor of the page shown when paging by cursor (Paging); null for the first page.string?
QueryPrefixPrefix for its query-string keys, so several can share a page: QueryPrefix="orders-" uses ?orders-page= (and a Table's ?orders-sort=).string""
EmptyContentShown when there are no items.RenderFragment?computed
EmptyTextThe text when there are no items.string?"No items"
ErrorContentShown in place of "Couldn't load the rows." when loading fails, before the Retry button.RenderFragment?
ItemKeyA unique, stable key for each item, such as its id.Func<TItem, string>?computed
LoadingShows it as loading: items dim, or placeholders show while there are none.boolfalse
SelectionModeWhether items can be selected: one (a radio button on each) or several (a checkbox on each).SelectionModeSelectionMode.None
SelectionNameThe form field name the selection posts under, read back as a Selection with [SupplyParameterFromForm(Name = ...)].string?computed
@bind-SelectionThe selected items: keys on any page, or every item matching the filter except some.Selection?
ItemSelectableWhether an item can be selected; others show a disabled, unchecked box, and selecting the page or a range leaves them out.Func<TItem, bool>?
SelectAllModeWhat the select-all checkbox selects: the items on this page, or every item the filters match, on any page.SelectAllModeSelectAllMode.Page
SelectionActionsActions on the selection, in a bar above the items, disabled until something is selected (on a DataGrid with a toolbar, the bar takes the toolbar's place while something is).RenderFragment<Selection>?
SelectAllLabelThe select-all checkbox's name for screen readers.string?"Select all rows"
SelectRowLabelThe start of each item checkbox's name for screen readers, before the item's label.string?"Select"
OnSaveSaves an edited row.EventCallback<DataGridSave<TItem>>
OnDeleteDeletes a row, once someone has confirmed it.EventCallback<DataGridDelete<TItem>>

See also

  • Table: sort, filter, page and select, with state in the URL.

Connection lost

Rejoining the server…