# DataGrid

Source: https://lumeo.nativ.sh/components/datagrid

# DataGrid

A powerful data grid with sorting, filtering, pagination, selection, inline editing, column pinning, resizable columns, row editing, layout persistence, context menus, and CSV/Excel/JSON export.

## Installation

.NET CLI PackageReference Lumeo CLI

dotnet add package Lumeo.DataGrid

One-time app setup (`AddLumeo()`, CSS & JS) is covered in the [installation guide](docs/introduction).

## Usage

@using Lumeo

<DataGrid />

**Dependencies & licensing — read carefully if you're shipping commercially.**

-   **ClosedXML** 0.104.2 (Excel `.xlsx` export) — MIT, fully free for any use.
-   **QuestPDF** 2024.12.3 (PDF export) — **dual-licensed**:
    -   **Free** for individual developers and for organizations with annual gross revenue under $1M USD (Community License).
    -   **Paid** ($699/dev/year as of writing) for everyone else — purchased direct from [questpdf.com](https://www.questpdf.com/license/). Lumeo doesn't take a cut.
-   CSV / JSON exports use built-in .NET serialization — no third-party dep, no licensing concern.

If you don't use the PDF export feature, the QuestPDF dependency is still loaded as a transitive package but never invoked — only calling `ExportPdfAsync` triggers the licensing requirement.  
  
**Since v3.7.0:** the export backend (ClosedXML + QuestPDF, ~1.65 MB brotli) ships as a separate bundled DLL inside `Lumeo.DataGrid` and can be lazy-loaded on Blazor WebAssembly — keep it out of the first paint and pull it in on the first export click. See the [lazy-loading setup guide](/docs/services/datagrid-export#lazy-loading).

## When to Use

-   Complex data grids with advanced features like sorting, filtering, and grouping
-   Enterprise table views with inline editing and cell-level validation
-   Column pinning and resizable columns for wide data sets
-   Scenarios requiring row selection, context menus, and data export (CSV/Excel/JSON)
-   Dashboards where the grid starts compact but the user can expand it to fullscreen for a full view

[

Try it

## Live playground

19 toggles, one live DataGrid. Flip search / grouping / pinning / pagination / edit mode and watch the grid re-render in real time.





](/components/datagrid/playground)

Preview Code

Basic DataGrid

Name

Department

Salary

Start Date

Alice Johnson

Engineering

¤95,000

2021-03-15

Bob Smith

Marketing

¤72,000

2020-07-01

Carol White

Engineering

¤105,000

2019-11-20

David Brown

Sales

¤68,000

2022-01-10

Eve Davis

Engineering

¤98,000

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

A simple data grid with sortable columns and pagination.

Preview Code

Column Groups + Footer Aggregates

Identity

Compensation

Name

Department

Salary

Tenure

Alice Johnson

Engineering

¤95,000

2021-03-15

Bob Smith

Marketing

¤72,000

2020-07-01

Carol White

Engineering

¤105,000

2019-11-20

David Brown

Sales

¤68,000

2022-01-10

Eve Davis

Engineering

¤98,000

2020-05-05

Sum: 1,045,000

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Wrap related columns under a labelled parent header that spans them via colspan. Set Aggregate=Sum / Average to get the sticky footer total row; FooterFormat lets totals format independently from cells (cells in C0, totals in N0).

Preview Code

Toolbar, Search & Filtering

Columns

Export

Name

Department

Salary

Status

Start Date

Alice Johnson

Engineering

¤95,000

Active

2021-03-15

Bob Smith

Marketing

¤72,000

Active

2020-07-01

Carol White

Engineering

¤105,000

Active

2019-11-20

David Brown

Sales

¤68,000

Inactive

2022-01-10

Eve Davis

Engineering

¤98,000

Active

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Enable the toolbar for global search, column visibility, and CSV export. Column filters appear as inline popovers.

## Toolbar customization

The toolbar is composed of independent slots — Search, Columns, Export, and Expand — each togglable with its own parameter. Defaults preserve the full toolbar; opt-out by setting any of `ShowSearch`, `ShowColumnChooser`, `ShowExport`, or `Expandable` to `false`. For fine-grained control over which file formats appear in the Export dropdown, use the `ExportFormats` flags enum. This is especially useful in Blazor WebAssembly, where PDF generators like QuestPDF throw `PlatformNotSupportedException` — hide PDF by setting `ExportFormats="DataGridExportFormat.Csv | DataGridExportFormat.Excel"`.

Preview Code

Minimal toolbar (search only)

Name

Department

Salary

Alice Johnson

Engineering

¤95,000

Bob Smith

Marketing

¤72,000

Carol White

Engineering

¤105,000

David Brown

Sales

¤68,000

Eve Davis

Engineering

¤98,000

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Hide the Columns and Export buttons to give users a cleaner toolbar with just global search.

Preview Code

Export-only toolbar

Export

Name

Department

Salary

Alice Johnson

Engineering

¤95,000

Bob Smith

Marketing

¤72,000

Carol White

Engineering

¤105,000

David Brown

Sales

¤68,000

Eve Davis

Engineering

¤98,000

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Hide the search input and Columns button to keep only the Export dropdown — useful for read-only, report-style grids.

Preview Code

CSV-only export (WASM-friendly)

Columns

Export

Name

Department

Salary

Alice Johnson

Engineering

¤95,000

Bob Smith

Marketing

¤72,000

Carol White

Engineering

¤105,000

David Brown

Sales

¤68,000

Eve Davis

Engineering

¤98,000

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Restrict the Export dropdown to CSV. Use this pattern in Blazor WebAssembly where PDF export libraries aren't supported.

## Filtering Extensibility

Column filters pick sensible defaults from `FilterType`, but two extension points let you customize the experience per-column without forking the grid.

### Restricting operators per column

Pass a `List<FilterOperator>` to the `Operators` parameter to limit which operators the built-in filter popover shows. The grid intersects this list with the defaults for the column's FilterType, so nonsensical combinations (e.g. `StartsWith` on a Number column) are filtered out automatically.

```
<DataGridColumnDef TItem="Employee"
                   Title="Name"
                   Field="Name"
                   Filterable="true"
                   Operators="@(new List<FilterOperator> { FilterOperator.Equals, FilterOperator.StartsWith })" />
```

### Custom filter UI via FilterTemplate

For columns that need a bespoke experience (range sliders, relative-date pickers, tag pickers, ...), supply a `FilterTemplate`. The render fragment receives a `DataGridFilterTemplateContext` exposing the field name, the currently-applied `FilterDescriptor` (or null), and an `Apply` callback. Invoke `Apply` with a descriptor to commit the filter, or with `null` to clear it.

```
<DataGridColumnDef TItem="Employee" Title="Salary" Field="Salary" Filterable="true">
    <FilterTemplate Context="ctx">
        <Slider Min="0" Max="200000" Value="_min" ValueChanged="v => _min = v" />
        <Button OnClick="@(async () => await ctx.Apply(
            new FilterDescriptor(ctx.Field!, FilterOperator.GreaterThanOrEqual, _min, FilterType: DataGridFilterType.Number)))">
            Apply
        </Button>
        <Button Variant="Button.ButtonVariant.Ghost" OnClick="@(async () => await ctx.Apply(null))">
            Clear
        </Button>
    </FilterTemplate>
</DataGridColumnDef>
```

What is _not_ pluggable today (tracked for a future release): registering brand-new `FilterOperator` values, combining column filters with OR logic, and LINQ-expression compilation for server-side evaluation. Filters are always AND-combined across columns; within a column you get one operator + value at a time.

Preview Code

Multi-Select with Checkboxes

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Select multiple rows with checkboxes. The header checkbox toggles select all.

Preview Code

Single Row Selection

Name

Department

Salary

Alice Johnson

Engineering

¤95,000

Bob Smith

Marketing

¤72,000

Carol White

Engineering

¤105,000

David Brown

Sales

¤68,000

Eve Davis

Engineering

¤98,000

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Click a row to select it. Useful for master-detail views.

Preview Code

Striped, Bordered & Compact

Name

Department

Salary

Status

Start Date

Alice Johnson

Engineering

¤95,000

Active

2021-03-15

Bob Smith

Marketing

¤72,000

Active

2020-07-01

Carol White

Engineering

¤105,000

Active

2019-11-20

David Brown

Sales

¤68,000

Inactive

2022-01-10

Eve Davis

Engineering

¤98,000

Active

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Visual variants for different density needs.

Preview Code

Custom Cell Templates

Actions

Salary

Status

¤95,000

Active

¤72,000

Active

¤105,000

Active

¤68,000

Inactive

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Use CellTemplate to render custom content like avatars, badges, and action buttons.

Preview Code

Expandable Detail Rows

Name

Department

Status

Alice Johnson

Engineering

Active

Bob Smith

Marketing

Active

Carol White

Engineering

Active

David Brown

Sales

Inactive

Eve Davis

Engineering

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Use DetailTemplate to show additional information when a row is expanded.

Preview Code

Column Pinning

Actions

Department

Salary

Status

Start Date

Engineering

¤95,000

Active

2021-03-15

Marketing

¤72,000

Active

2020-07-01

Engineering

¤105,000

Active

2019-11-20

Sales

¤68,000

Inactive

2022-01-10

Engineering

¤98,000

Active

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Pin columns to the left or right edge so they stay visible while scrolling horizontally.

Preview Code

Resizable Columns

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Drag the column border to resize. All columns are resizable by default. Use MinWidth and MaxWidth to constrain sizing.

Preview Code

Inline Cell Editing

Name

Department

Status

Alice Johnson

Engineering

Active

Bob Smith

Marketing

Active

Carol White

Engineering

Active

David Brown

Sales

Inactive

Eve Davis

Engineering

Active

Rows per page

5

1–5 of 5

-   Previous
-   1
-   Next

Click a cell to edit it inline. Press Enter to commit, Escape to cancel.

Preview Code

Batch / Buffered Editing

Name

Department

Status

Alice Johnson

Engineering

Active

Bob Smith

Marketing

Active

Carol White

Engineering

Active

Add row

Rows per page

5

1–3 of 3

-   Previous
-   1
-   Next

Edit cells inline as in Cell mode, but commits land in a per-row pending-changes buffer. A pending strip and Save all / Discard buttons appear above the grid. Optional + Add row trigger pushes new rows into the Added buffer. OnBatchSave receives Modified + Added when the user clicks Save all.

Preview Code

Row Editing

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 5

-   Previous
-   1
-   Next

Edit an entire row at once. Click the edit button to enter edit mode, then save or cancel.

Preview Code

Footer Aggregation

Name

Department

Salary

Start Date

Alice Johnson

Engineering

¤95,000

2021-03-15

Bob Smith

Marketing

¤72,000

2020-07-01

Carol White

Engineering

¤105,000

2019-11-20

David Brown

Sales

¤68,000

2022-01-10

Eve Davis

Engineering

¤98,000

2020-05-05

Frank Wilson

Marketing

¤75,000

2021-08-22

Grace Lee

Sales

¤82,000

2019-06-30

Henry Taylor

Engineering

¤110,000

2018-09-12

Ivy Martinez

Marketing

¤71,000

2022-04-18

Jack Anderson

Sales

¤88,000

2020-12-03

Kate Thomas

Engineering

¤102,000

2021-02-14

Leo Jackson

Sales

¤79,000

2019-10-08

Count: 12

Avg: ¤87,083

Rows per page

20

1–12 of 12

-   Previous
-   1
-   Next

Show computed summaries (Sum, Average, Count, Min, Max) in the table footer.

Preview Code

Row Grouping

Group by:

Department

Expanded by default

Name

Department

Status

Salary

Start Date

Alice Johnson

Engineering

Active

¤95,000

2021-03-15

Bob Smith

Marketing

Active

¤72,000

2020-07-01

Carol White

Engineering

Active

¤105,000

2019-11-20

David Brown

Sales

Inactive

¤68,000

2022-01-10

Eve Davis

Engineering

Active

¤98,000

2020-05-05

Frank Wilson

Marketing

Active

¤75,000

2021-08-22

Grace Lee

Sales

Active

¤82,000

2019-06-30

Henry Taylor

Engineering

Active

¤110,000

2018-09-12

Ivy Martinez

Marketing

Inactive

¤71,000

2022-04-18

Jack Anderson

Sales

Active

¤88,000

2020-12-03

Avg: ¤87,083

Rows per page

10

1–10 of 12

-   Previous
-   1
-   2
-   Next

Group rows by a field. Click the group header to expand or collapse each group. Set GroupsExpandedByDefault to control the initial state.

Preview Code

Group Panel (Interactive)

Group panel:

Off On

Levels:

Single (Department) Multi (Department → Status)

Drag a Groupable column header here, or use the dropdown

\+ Add group level

Name

Department

Status

Salary

Start Date

Alice Johnson

Engineering

Active

¤95,000

2021-03-15

Bob Smith

Marketing

Active

¤72,000

2020-07-01

Carol White

Engineering

Active

¤105,000

2019-11-20

David Brown

Sales

Inactive

¤68,000

2022-01-10

Eve Davis

Engineering

Active

¤98,000

2020-05-05

Frank Wilson

Marketing

Active

¤75,000

2021-08-22

Grace Lee

Sales

Active

¤82,000

2019-06-30

Henry Taylor

Engineering

Active

¤110,000

2018-09-12

Ivy Martinez

Marketing

Inactive

¤71,000

2022-04-18

Jack Anderson

Sales

Active

¤88,000

2020-12-03

Avg: ¤87,083

Rows per page

10

1–10 of 12

-   Previous
-   1
-   2
-   Next

Set ShowGroupPanel=&quot;true&quot; to render the chip-strip panel above the grid. Flag columns Groupable=&quot;true&quot; to make them addable. Use GroupByFields for ordered multi-level grouping — each level adds a nested row with its own aggregate.

Preview Code

Column Reordering

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Drag column headers to reorder them. Enable with the Reorderable property on the grid.

Preview Code

Conditional Row Styling

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Apply dynamic CSS classes or inline styles to rows based on data. Useful for highlighting specific records.

Preview Code

Context Menu

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Right-click a row to open a custom context menu with actions.

Preview Code

Layout Persistence

Columns

Export

Layouts

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Save and restore column widths, order, visibility, sorts, filters, and the group panel (runtime group fields) to localStorage. The layout survives page refreshes. Use the Layouts dropdown in the toolbar to save named layouts under Personal, Global, or System Default scopes.

Preview Code

Named Layout Manager

Columns

Export

Layouts

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Pass GlobalLayouts to surface pre-built layouts in the Layouts dropdown. Users can also save their own Personal layouts which are stored in localStorage. The panel shows Personal / Global / System Default scopes.

## Saving and loading layouts

For full control over where layouts are stored (your own database, a REST API, cookies, etc.), use the programmatic JSON API. Capture a grid reference with `@ref`, then call `ExportLayout()` to get a JSON string and `ApplyLayoutJsonAsync(json)` to round-trip it later. The snapshot covers column order, widths, visibility, pin state, sorts, filters, global search, current page, page size, and the group panel (multi-level group fields) — both single and multi-level grouping levels round-trip.

```
<DataGrid @ref="_grid" TItem="Order" Items="_orders">
    <DataGridColumnDef TItem="Order" Field="Id" Title="ID" />
    <DataGridColumnDef TItem="Order" Field="Customer" Title="Customer" />
    <DataGridColumnDef TItem="Order" Field="Total" Title="Total" Format="C2" />
</DataGrid>

<Button OnClick="SaveLayout">Save layout</Button>
<Button OnClick="LoadLayout">Load layout</Button>

@code {
    private DataGrid<Order>? _grid;
    [Inject] MyAppDbContext Db { get; set; } = default!;

    private async Task SaveLayout()
    {
        if (_grid is null) return;
        var json = _grid.ExportLayout();
        await Db.UserLayouts.AddAsync(new UserLayout {
            UserId = CurrentUserId,
            GridKey = "orders",
            Json = json,
            SavedAt = DateTime.UtcNow
        });
        await Db.SaveChangesAsync();
    }

    private async Task LoadLayout()
    {
        if (_grid is null) return;
        var latest = await Db.UserLayouts
            .Where(l => l.UserId == CurrentUserId && l.GridKey == "orders")
            .OrderByDescending(l => l.SavedAt)
            .FirstOrDefaultAsync();
        if (latest is not null)
            await _grid.ApplyLayoutJsonAsync(latest.Json);
    }
}
```

The JSON shape is the public `DataGridLayoutSnapshot` record. The snapshot is versioned (`Version: 2` today) so future breaking changes can be migrated; v1 payloads still load — the legacy single-level `GroupBy` field is honoured as a fallback when `GroupByFields` is absent. Columns referenced in a snapshot that no longer exist on the grid are silently ignored; columns present on the grid but missing from the snapshot are appended at the end.

## Reorder columns

Set `Reorderable="true"` on the grid to enable column reordering. Users can reorder columns two ways:

-   **Drag-and-drop**: grab a column header and drag it left or right. A 2px vertical drop indicator renders at the nearest column boundary to show where the column will land when released.
-   **Keyboard / menu arrows**: open the Toggle Columns popover from the toolbar and use the up/down arrow buttons next to each column. This path is the accessible fallback for users who can't use pointer drag-and-drop.

To pin an individual column so it cannot be reordered (for example, a required identifier column), set `Reorderable="false"` on that `DataGridColumnDef`. Both the drag handle and the menu arrows respect this flag.

```
<DataGrid TItem="Order" Items="_orders" Reorderable="true">
    <DataGridColumnDef TItem="Order" Field="Id" Title="ID" Reorderable="false" />
    <DataGridColumnDef TItem="Order" Field="Customer" Title="Customer" />
    <DataGridColumnDef TItem="Order" Field="Total" Title="Total" Format="C2" />
</DataGrid>
```

Preview Code

Custom Toolbar Content

Add Employee

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

The ToolbarContent component slots your custom buttons next to the toolbar's filter chips. Use the Class attribute to tweak the wrapper (gap, flex-wrap, etc.).

Preview Code

Composing Toolbar Tools

Refresh

Columns

Export

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Mix your own buttons with built-in tools. When you provide ToolbarContent, the default tool stack is suppressed — you pick exactly which tools to include and in what order. Each tool picks up the grid's state via a cascading context — no props needed.

Grouping in ServerMode

**`GroupBy`, `GroupByFields`, and the runtime group panel (`ShowGroupPanel="true"`) all work in `ServerMode` — including drag-to-group, add-level dropdown, per-chip remove, and clear-all.** Grouping is applied client-side to whatever rows the server returned for the current page. For grouping across the whole dataset, either set `ShowPagination="false"` (server returns all rows) or have the server pre-aggregate groups itself.

Preview Code

Server-Side Mode

Columns

Export

Name

Department

Salary

Status

Rows per page

5

0–0 of 0

-   Previous
-   1
-   Next

For large datasets, use ServerMode to handle sorting, filtering, and pagination on the server. Sorting, filtering, search, and pagination all trigger OnServerRequest. Loading state and request cancellation are managed automatically.

Preview Code

Server-Side Error Handling

Simulate server error

Name

Department

Salary

Status

Rows per page

5

0–0 of 0

-   Previous
-   1
-   Next

Toggle the simulate error button to trigger a server failure. OnError receives the exception so you can display a message outside the grid.

Preview Code

Multi-Sort

Department

Name

Salary

Start Date

Engineering

Alice Johnson

¤95,000

2021-03-15

Marketing

Bob Smith

¤72,000

2020-07-01

Engineering

Carol White

¤105,000

2019-11-20

Sales

David Brown

¤68,000

2022-01-10

Engineering

Eve Davis

¤98,000

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Click multiple column headers to sort by multiple fields. The grid applies sorts in the order they were added. Click a column again to cycle through ascending, descending, and unsorted.

## Virtualization & large datasets

Lumeo's DataGrid supports two distinct strategies for large datasets — pick the one that matches where your data lives:

-   **Client virtualization** — items are already in memory. Set `ShowPagination="false"` and pass all rows; once the row count exceeds `VirtualizeThreshold` (default 500), Blazor's built-in `<Virtualize>` renders only the rows in the viewport. Tune `VirtualItemSize` if your rows are denser/taller than the 41 px default — an inaccurate value makes the scrollbar drift. Paged grids never trigger this path because they only render `PageSize` rows at a time.
-   **Server-side paging** — items live on a backend. Set `ServerMode="true"`, handle `OnServerRequest` (Skip/Take/Sort/Filter), and report `TotalCount`. The grid shows numbered pages and the `PageSizeOptions` selector. Use this when you have many pages of data but only want to fetch one page at a time.

-   **Virtualised server mode (infinite scroll)** — the third mode. Set `Virtualized="true"` + provide an `OnRangeRequest` callback. The grid drops pagination, renders one tall scrollable body, and fetches a sliding window of rows from your backend as the user scrolls. Sort, column filters and global search all trigger an automatic refetch via `Virtualize.RefreshDataAsync()` — no manual wiring needed. Use this when you have hundreds of thousands of rows and want a grid that feels native, not paged.

Preview Code

Virtualised server mode (infinite scroll)

Columns

Export

Name

Department

Salary

Status

No data available

Set Virtualized=true + provide OnRangeRequest. The grid fetches a sliding window of rows from your backend as the user scrolls, hides pagination, and re-fetches automatically when sort/filter/search change. Demo fakes a 50000-row backend with an in-memory list.

Preview Code

Custom page-size options

Name

Department

Salary

Status

Alice Johnson

Engineering

¤95,000

Active

Bob Smith

Marketing

¤72,000

Active

Carol White

Engineering

¤105,000

Active

David Brown

Sales

¤68,000

Inactive

Eve Davis

Engineering

¤98,000

Active

Frank Wilson

Marketing

¤75,000

Active

Grace Lee

Sales

¤82,000

Active

Henry Taylor

Engineering

¤110,000

Active

Ivy Martinez

Marketing

¤71,000

Inactive

Jack Anderson

Sales

¤88,000

Active

Rows per page

10

1–10 of 12

-   Previous
-   1
-   2
-   Next

Pass a custom array to the rows-per-page selector — useful for grids with many rows where 100 isn't enough. Empty array hides the selector.

Preview Code

Fixed Height with Scroll

Name

Department

Salary

Status

Start Date

Alice Johnson

Engineering

¤95,000

Active

2021-03-15

Bob Smith

Marketing

¤72,000

Active

2020-07-01

Carol White

Engineering

¤105,000

Active

2019-11-20

David Brown

Sales

¤68,000

Inactive

2022-01-10

Eve Davis

Engineering

¤98,000

Active

2020-05-05

Frank Wilson

Marketing

¤75,000

Active

2021-08-22

Grace Lee

Sales

¤82,000

Active

2019-06-30

Henry Taylor

Engineering

¤110,000

Active

2018-09-12

Ivy Martinez

Marketing

¤71,000

Inactive

2022-04-18

Jack Anderson

Sales

¤88,000

Active

2020-12-03

Kate Thomas

Engineering

¤102,000

Active

2021-02-14

Leo Jackson

Sales

¤79,000

Active

2019-10-08

Set a fixed height on the grid to enable vertical scrolling for long lists.

Preview Code

Loading State

Name

Department

Salary

Status

Show skeleton rows while data is loading.

Preview Code

Empty State

Name

Department

No employees found. Try adjusting your filters.

Rows per page

5

0–0 of 0

-   Previous
-   1
-   Next

Custom content when the grid has no data.

Preview Code

Expandable (Fullscreen)

Columns

Export

Name

Department

Salary

Status

Start Date

Alice Johnson

Engineering

¤95,000

Active

2021-03-15

Bob Smith

Marketing

¤72,000

Active

2020-07-01

Carol White

Engineering

¤105,000

Active

2019-11-20

David Brown

Sales

¤68,000

Inactive

2022-01-10

Eve Davis

Engineering

¤98,000

Active

2020-05-05

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

Enable the Expandable feature to add a fullscreen icon in the toolbar. Click it to pop the grid into a fullscreen modal overlay. Selection, filters, sorts, and pagination all survive the transition. Press Esc or click the close button to exit.

Preview Code

Full-Featured DataGrid

Columns

Export

Employee

Department

Salary

Status

Start Date

AL

Alice Johnson

Engineering

¤95,000

Active

2021-03-15

BO

Bob Smith

Marketing

¤72,000

Active

2020-07-01

CA

Carol White

Engineering

¤105,000

Active

2019-11-20

DA

David Brown

Sales

¤68,000

Inactive

2022-01-10

EV

Eve Davis

Engineering

¤98,000

Active

2020-05-05

Avg: ¤87,083

Rows per page

5

1–5 of 12

-   Previous
-   1
-   2
-   3
-   Next

All features combined: toolbar, search, filtering, sorting, selection, column visibility, export, conditional styling, and aggregation.

## API Reference

### DataGrid<TItem>

Property

Type

Default

Description

Items

IEnumerable<TItem>?

\--

Data source for the grid.

Columns

List<DataGridColumn<TItem>>?

\--

Programmatic column definitions (alternative to DataGridColumnDef).

PageSize

int

10

Number of rows per page.

ShowPagination

bool

true

Show pagination controls.

ShowToolbar

bool

false

Show toolbar with search, export, and column visibility.

ShowSearch

bool

true

Show the global search box in the toolbar. Requires `ShowToolbar`.

ShowColumnChooser

bool

true

Show the Columns (visibility/reorder) button in the toolbar.

ShowExport

bool

true

Show the Export button and its format dropdown. Set `false` to hide export entirely; for per-format control see `ExportFormats`.

ExportFormats

DataGridExportFormat

All

Flags enum controlling which formats appear in the Export dropdown. Combine with bitwise OR, e.g. `DataGridExportFormat.Csv | DataGridExportFormat.Excel`. When no flags are set the Export button is hidden.

SelectionMode

DataGridSelectionMode

None

Row selection: None, Single, or Multiple.

EditMode

DataGridEditMode

None

Inline editing: None, Cell, Row, or Batch (buffered).

OnBatchSave

EventCallback<DataGridBatchSaveEventArgs<TItem>>

\--

Fires when the user clicks "Save all" in `EditMode=Batch`. Carries `Modified` + `Added` rows. The grid's pending-changes buffer is cleared automatically on a clean return.

ShowAddRow

bool

false

Renders a "+ Add row" trigger below the body in batch mode. Requires `NewItemFactory`.

NewItemFactory

Func<TItem>?

\--

Factory used by the "+ Add row" trigger. Each click produces a fresh row that lives in the batch buffer until `OnBatchSave` commits it.

HasPendingChanges

bool (get)

\--

True when the batch buffer contains a buffered edit or a new row. Bind via `@ref` for warn-on-navigate workflows.

BatchSaveAllText / BatchDiscardText / BatchAddRowText

string?

Save all / Discard / Add row

Button labels for the batch-mode toolbar. Override for localization.

ColumnVirtualize

bool

false

Simplified column virtualization — caps the number of horizontally-rendered data columns at `MaxVisibleColumns`. Pinned columns always render. Useful for very wide grids.

MaxVisibleColumns

int

30

Column cap used when `ColumnVirtualize=true`.

Striped

bool

false

Alternate row background colors.

Bordered

bool

false

Show cell borders.

Compact

bool

false

Smaller row height and text.

Hoverable

bool

true

Highlight rows on hover.

Height

string?

\--

Fixed height with scrollable body (e.g., "400px").

Reorderable

bool

false

Enable drag-and-drop column reordering.

RowReorderable

bool

false

Enable drag-and-drop row reordering.

RowClass

Func<TItem, string>?

\--

Function returning CSS class(es) for each row.

RowStyle

Func<TItem, string>?

\--

Function returning inline style for each row.

PageSizeOptions

int\[\]

\[10, 25, 50, 100\]

Page-size options shown in the rows-per-page selector. Pass `new[] { 10, 50, 100, 200, 300 }` for larger datasets, or an empty array to hide the selector entirely.

VirtualizeThreshold

int

500

Row count above which Blazor's `<Virtualize>` kicks in. Only relevant when `ShowPagination=false` — paged grids never reach the threshold and never virtualize.

VirtualItemSize

float

41

Estimated row height in CSS pixels. Tune if rows are denser/taller than the default.

VirtualOverscanCount

int

3

Extra rows rendered above/below the viewport to hide pop-in during fast scrolling.

Virtualized

bool

false

Enables ItemsProvider-based infinite-scroll mode. Hides pagination and fetches a sliding row window via `OnRangeRequest` as the user scrolls. Sort/filter/search refresh the virtualizer automatically.

OnRangeRequest

Func<DataGridRangeRequest, ValueTask<DataGridRangeResponse<TItem>>>?

\--

Range-fetch callback for virtualised server mode. Receives `StartIndex`, `Count`, current Sort/Filter/Search context; must return the slice plus current `TotalCount`.

ServerMode

bool

false

Enable server-side sorting, filtering, and pagination.

TotalCount

int

0

Total item count for server-side pagination.

IsLoading

bool

false

Show loading skeleton overlay.

EnableLayoutPersistence

bool

false

Auto-save/restore column layout to localStorage. Enables the Layouts dropdown in the toolbar.

LayoutStorageKey

string?

auto

Custom localStorage key for layout persistence.

SavedLayout

DataGridLayout?

\--

Externally provided layout to apply on load.

GlobalLayouts

List<DataGridNamedLayout>?

\--

Pre-built named layouts shown in the Global scope of the Layouts panel.

OnSaveNamedLayout

EventCallback<DataGridNamedLayout>

\--

Fires when the user saves a named layout. Personal layouts are also persisted to localStorage automatically.

OnDeleteNamedLayout

EventCallback<string>

\--

Fires when the user deletes a named layout. Receives the layout Id.

DetailTemplate

RenderFragment<TItem>?

\--

Template for expandable row details.

EmptyContent

RenderFragment?

\--

Custom content when no data.

<ToolbarContent>

component

\--

Nested component placed inside ChildContent. Takes Class for wrapper styling and ChildContent for custom buttons / built-in toolbar tools.

RowContextMenu

RenderFragment<TItem>?

\--

Right-click context menu template for rows.

OnRowClick

EventCallback<TItem>

\--

Callback when a row is clicked.

OnRowDoubleClick

EventCallback<TItem>

\--

Callback when a row is double-clicked.

OnCellEdit

EventCallback<CellEditEventArgs<TItem>>

\--

Callback when a cell edit is committed.

OnRowEdit

EventCallback<RowEditEventArgs<TItem>>

\--

Callback when a row edit is committed with all changed values.

OnColumnReorder

EventCallback<ColumnReorderEventArgs>

\--

Callback when columns are reordered via drag-and-drop.

OnRowReorder

EventCallback<RowReorderEventArgs<TItem>>

\--

Callback when rows are reordered via drag-and-drop.

OnLayoutSave

EventCallback<DataGridLayout>

\--

Fires when the layout is saved (for external persistence).

SelectedItems

IReadOnlyList<TItem>?

\--

Two-way bindable selected items collection.

SelectedItemsChanged

EventCallback<IReadOnlyList<TItem>>

\--

Callback when selection changes.

OnServerRequest

EventCallback<DataGridServerRequest>

\--

Server-side data request callback with sorts, filters, page info.

OnError

EventCallback<Exception>

\--

Fires when a server request throws an exception.

GroupBy

string?

\--

Single-level group field. Works in both client and `ServerMode`; use `GroupByFields` for multi-level.

Expandable

bool

false

Adds an expand icon to the toolbar for toggling fullscreen mode.

IsExpanded

bool

false

Two-way bindable fullscreen state. Set from code to programmatically expand/collapse.

IsExpandedChanged

EventCallback<bool>

\--

Fires whenever the fullscreen state toggles.

FullscreenTitle

string?

\--

Optional title shown in the fullscreen header bar. Defaults to "Data Grid".

Class

string?

\--

Additional CSS classes for the root element.

ExportLayout()

string

method

Serializes the current layout (column order, widths, visibility, pin state, sorts, filters, global search, page, page size, group-by) to a JSON string. Call via `@ref`.

ApplyLayoutJsonAsync(json)

Task

method

Deserializes a JSON layout produced by `ExportLayout` and applies it. Throws `JsonException` on malformed input; silently ignores columns that no longer exist.

GroupsExpandedByDefault

bool

true

Initial expand state for group headers when grouping is active.

### ToolbarContent<TItem>

Place inside `<ChildContent>` of a DataGrid. Accepts custom buttons or built-in toolbar tool components (see below) that automatically pick up the grid's state via a cascading context.

Property

Type

Default

Description

Class

string?

\--

CSS classes applied to the wrapper around ChildContent + the toolbar's filter chips.

ChildContent

RenderFragment?

\--

Your custom buttons and any of the built-in toolbar tool components.

### Toolbar Tool Components

Built-in tool components you can drop inside `<ToolbarContent>`. Each takes only `TItem` and reads everything else (selection, columns, export formats, layout config, Interop, Localizer) from a cascading `DataGridToolbarContext<TItem>`.

Component

Renders

Visible when

<DataGridToolbarFullscreen>

Fullscreen toggle icon button.

`Expandable="true"` on the grid.

<DataGridToolbarCopySelected>

Copy-to-clipboard button (tab-separated, selected rows).

At least one row is selected.

<DataGridToolbarColumns>

Column visibility + reorder dropdown.

Always (gate on the grid via `ShowColumnChooser`).

<DataGridToolbarExport>

Export dropdown (CSV / Excel / PDF per `ExportFormats`).

`ExportFormats != None`.

<DataGridToolbarLayouts>

Saved-layouts panel (personal + global).

`EnableLayoutPersistence="true"`.

Omit `<ToolbarContent>` and all five tools auto-render in the default order (Fullscreen, CopySelected, Columns, Export, Layouts) gated by their `Show*` flags on the DataGrid. Provide `<ToolbarContent>` and the default stack is suppressed entirely — you pick which tools to include and where, no duplicates.

### DataGridColumnDef<TItem>

Property

Type

Default

Description

Title

string?

\--

Column header text.

Field

string?

\--

Property name to bind to on TItem.

FieldSelector

Func<TItem, object?>?

\--

Custom value accessor (alternative to Field).

Width

double?

\--

Column width in pixels.

MinWidth

double?

\--

Minimum column width in pixels during resize.

MaxWidth

double?

\--

Maximum column width in pixels during resize.

Sortable

bool

false

Enable sorting for this column.

Filterable

bool

false

Enable filtering for this column.

Resizable

bool

true

Allow column resizing via drag handle.

Pin

PinDirection

None

Pin column: None, Left, or Right.

Pinnable

bool

false

Whether column can be pinned/unpinned via the UI.

Groupable

bool

false

Whether column can be used for grouping.

Reorderable

bool

true

Whether this column can be reordered (via header drag-and-drop or the Toggle Columns menu arrows). Set to `false` to pin an individual column's position even when the grid-level `Reorderable` is true.

FilterType

DataGridFilterType

Text

Filter input type: Text, Number, Date, Select, Boolean.

FilterOptions

List<FilterOption>?

\--

Options for Select filter type (label + value pairs).

Operators

List<FilterOperator>?

\--

Optional whitelist of operators to show in the filter UI for this column. When null, defaults for the FilterType are used.

FilterTemplate

RenderFragment<DataGridFilterTemplateContext>?

\--

Custom filter UI for this column. Replaces the built-in operator + value inputs when provided. Invoke the context's Apply callback with a FilterDescriptor to commit, or null to clear.

Format

string?

\--

Format string (e.g., "C0", "yyyy-MM-dd", "N2").

Aggregate

AggregateType

None

Footer aggregate: None, Sum, Average, Count, Min, Max.

CustomSort

Comparison<object?>?

\--

Custom sort comparison function for this column.

CellClass

Func<TItem, string>?

\--

Function returning dynamic CSS class(es) for each cell.

HeaderCssClass

string?

\--

Custom CSS class for the header cell.

CellTemplate

RenderFragment<TItem>?

\--

Custom render template for cell content.

HeaderTemplate

RenderFragment?

\--

Custom render template for header.

EditTemplate

RenderFragment<CellEditContext<TItem>>?

\--

Custom template for inline editing input.

### Event Args

Type

Properties

Description

CellEditEventArgs<TItem>

Item, Field, OldValue, NewValue

Fired when a cell edit is committed.

RowEditEventArgs<TItem>

Item, ChangedValues

Fired when a row edit is committed. ChangedValues is a Dictionary<string, object?>.

ColumnReorderEventArgs

ColumnId, OldIndex, NewIndex

Fired when a column is drag-reordered.

RowReorderEventArgs<TItem>

Item, OldIndex, NewIndex

Fired when a row is drag-reordered.

DataGridServerRequest

Page, PageSize, Sorts?, Filters?, GlobalSearch?, GroupBy?, CancellationToken

Sent to OnServerRequest with current grid state. GroupBy contains the current group field if set. CancellationToken should be passed to your HTTP client to abort superseded requests.

DataGridLayout

Columns, Sorts?, Filters?, PageSize?, GlobalSearch?

Serializable layout snapshot for persistence.

DataGridNamedLayout

Id, Name, Scope, Layout

A named layout entry. Scope is "Personal", "Global", or "SystemDefault".

DataGridLayoutSnapshot

Version, Columns, Sorts, Filters, GlobalSearch?, CurrentPage, PageSize, GroupBy?

Public, JSON-serializable shape used by `ExportLayout`/`ApplyLayoutJsonAsync`. Version is bumped on schema changes.

DataGridColumnLayout

Field, Order, Visible, Width?, Pin?

Per-column entry inside a `DataGridLayoutSnapshot`.

### Enums

DataGridSelectionMode

None

No selection.

Single

Select one row at a time.

Multiple

Select multiple rows with checkboxes.

PinDirection

None

Column scrolls normally.

Left

Sticky to left edge.

Right

Sticky to right edge.

DataGridEditMode

None

No editing.

Cell

Click a cell to edit inline.

Row

Edit entire row at once.

AggregateType

None

No aggregation.

Sum

Sum of numeric values.

Average

Average of numeric values.

Count

Count of non-null values.

Min

Minimum value.

Max

Maximum value.

### DataGridFilterType

Value

Description

Text

Text filter with contains, starts with, equals operators.

Number

Numeric filter with comparison and between operators.

Date

Date filter with date picker and comparison operators.

Select

Multi-select checkbox filter from predefined options.

Boolean

True/false toggle filter.

## Tree-grid mode (hierarchical rows)

Set `ChildItemsSelector` to a function that returns a row's children (`null`/empty for leaves) and the grid renders a recursive tree-grid: the first visible column gets an expand/collapse chevron indented by depth, the `<table>` uses `role="treegrid"`, and expandable rows carry `aria-expanded` / `aria-level`. Sorting, filtering and paging apply to the _root_ items; a paged-in root shows its whole expanded subtree. Tree-grid mode and `DetailTemplate` master-detail are mutually exclusive — tree mode wins.

Parameter

Type

Description

ChildItemsSelector

Func<TItem, IEnumerable<TItem>?>?

When set, enables tree-grid mode; returns a row's child rows.

TreeGridDefaultExpanded

bool

Whether tree nodes start expanded. Default `false`.

TreeColumnField

string?

Field of the column carrying the chevron + indentation. Null = first visible column.

OnTreeNodeExpand

EventCallback<TItem>

Raised when a tree node is expanded or collapsed.

## Group panel & multi-level grouping

Set `ShowGroupPanel="true"` to render a strip above the grid listing the active grouping levels as removable chips, plus an "add level" dropdown of every column flagged `Groupable`. Use `GroupByFields` (an ordered list of column fields) for nested multi-level grouping — the grid renders nested group rows with increasing indentation and a per-group aggregate row (the same `Column.Aggregate` values as the grand-total footer, computed over each group). A single-element list (or the legacy `GroupBy` string) keeps the classic single-level grouping.

**Works in `ServerMode` too.** Both single-level `GroupBy` and multi-level `GroupByFields` are applied client-side to whatever rows the server returned, and the runtime panel handlers (drag-to-add, add-level dropdown, per-chip remove, clear-all) trigger an in-place regroup without an extra server round-trip. Grouping operates over the _current page_ only — for cross-page grouping, either disable pagination (`ShowPagination="false"`) so the server delivers all rows in one response, or have the server pre-aggregate groups itself.

Parameter

Type

Description

ShowGroupPanel

bool

Shows the grouping chip strip + add-level dropdown. Default `false`.

GroupByFields

IReadOnlyList<string>?

Ordered column fields for multi-level grouping; takes precedence over `GroupBy`. Works in both client and `ServerMode` (grouping runs over the rows the server returned for the current page).

GroupPanelText

string?

Placeholder hint shown in the panel when nothing is grouped.

Column.Groupable

bool

Gates whether a column can be added to the group panel.

## Related Components

-   [DataTable](/components/data-table) — A simpler table component for basic tabular data without advanced grid features
-   [Table](/components/table) — Low-level table building blocks for fully custom table layouts
-   [Pagination](/components/pagination) — Standalone pagination control for navigating through paged data
