DevExpress Blazor Grid
SkillSearchBuild and configure the DevExpress Blazor Grid (DxGrid) — a full-featured data grid for Blazor Server, WebAssembly, and Hybrid apps. Use when binding tabular data (IEnumerable/IQueryable/EF Core/server-mode/custom sources), enabling sorting/filtering/grouping/search, implementing CRUD editing (row/edit form/popup/cell), handling selection and focused rows, exporting to CSV/XLSX/PDF, customizing templates and summaries, and supporting large datasets with virtualization. Also use for DxGrid, DevExpress grid, Blazor data grid, virtual scrolling, server mode, and grid feature comparisons or migration scenarios.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the DevExpress Blazor Grid skill
What this skill tells your AI
The instructions your AI receives, as published by devexpress/agent-skills in plugins/dx-blazor/skills/devexpress-blazor-grid/SKILL.md and read by ahel’s review.
DxGrid is a high-performance data grid for Blazor applications. It supports data binding to in-memory collections, Entity Framework Core, server-mode sources, and custom data sources. Key feature areas include sorting, grouping, filtering, multi-mode editing (edit row, edit form, popup, cell), row selection, data export (CSV/XLS/PDF), column templates, summaries, and drag-and-drop row reordering.
When to Use This Skill
- Display tabular data from any .NET data source in a Blazor page
- Implement CRUD operations (create, update, delete rows) with built-in edit forms
- Sort, group, filter, and search grid data in the UI or programmatically
- Export data to CSV, XLSX, or PDF with custom formatting
- Enable row selection (single or multiple) and act on selected data
- Add column chooser, resize, reorder, and freeze (pin) columns
- Use virtual scrolling for large in-memory datasets
- Bind to large remote datasets via EF Core server-mode sources
- Customize cell appearance using templates and
CustomizeElement - Add a toolbar, context menu, or summary rows to the grid
Prerequisites & Installation
NuGet Package
| Package | Purpose |
|---|---|
DevExpress.Blazor | Grid + all standard Blazor UI components |
# Install from NuGet.org:
dotnet add package DevExpress.Blazor
Setup (existing project)
- Register DevExpress resources in
Program.cs:builder.Services.AddDevExpressBlazor();v26.1 note:
DevExpress.Blazorno longer includesoptions.BootstrapVersionorDevExpress.Blazor.BootstrapVersion. Do not generate either API. - Apply a theme and add client scripts in
App.razorinside<head>:@using DevExpress.Blazor @DxResourceManager.RegisterTheme(Themes.Fluent) @DxResourceManager.RegisterScripts() - Add the namespace to
_Imports.razor:@using DevExpress.Blazor
Before You Start — Ask the Developer
If the host agent has a structured question-asking tool available, use it to ask these questions one at a time with clear options — for example, Claude Code's AskUserQuestion tool or GitHub Copilot's askQuestions tool. If no such tool is available, ask the questions directly in the chat response before generating code.
Before generating code, ask:
- Render mode: Are you using
InteractiveServer,InteractiveWebAssembly, orInteractiveAuto? (Grid requires an interactive mode for sorting, filtering, editing, and paging.) - Data source: Are you binding to a simple in-memory collection (
List<T>,IEnumerable<T>), EF Core (DbSet<T>orEntityInstantFeedbackSource),IQueryable<T>, or a custom data source (GridCustomDataSource)? - Features needed: Do you need editing (which mode: EditRow, EditForm, PopupEditForm, EditCell)? Export? Selection? Virtual scrolling?
- Key field: Does your data model have a primary key property? (Required for editing, selection, and server-mode sources.)
- New or existing project?: Are you adding the grid to an existing project or starting fresh?
Ask before generating. Render mode and data source type significantly affect the code.
Component Overview
DxGrid provides:
- Data Binding (
Data,KeyFieldName): Binds toIEnumerable<T>,IListSource,IQueryable<T>,GridDevExtremeDataSource<T>, orGridCustomDataSource - Column Types (
DxGridDataColumn,DxGridCommandColumn,DxGridSelectionColumn,DxGridBandColumn): Bound, unbound, command, selection, and band columns - Data Shaping (
AllowSort,ShowGroupPanel,ShowSearchBox,FilterPanelDisplayMode): Sort, group, filter row, filter panel, search box - Editing (
EditMode,EditModelSaving,DataItemDeleting): EditRow, EditForm, PopupEditForm, EditCell modes - Selection (
SelectionMode,SelectedDataItems): Single and multiple row selection - Export (
ExportToCsvAsync,ExportToXlsxAsync,ExportToPdfAsync): CSV, XLS/XLSX, and PDF export - Paging & Scrolling (
PageSize,VirtualScrollingEnabled,VirtualScrollingMode): Pager and virtual scrolling - Summary (
TotalSummary,GroupSummary,DxGridSummaryItem): Total and group aggregate summaries — Sum, Min, Max, Avg, Count — displayed in the grid footer - Focused Row (
FocusedRowEnabled): Highlights a single row on click; exposesFocusedRowIndexandFocusedDataItemfor programmatic access - Toolbar (
ToolbarTemplate): Embed a toolbar at the top of the Grid with custom action buttons and data shaping controls - Master-Detail (
DetailRowTemplate,ExpandDetailRow,CollapseDetailRow): Expandable detail rows with nested grids or arbitrary content; the detail template receives the master row's data item viacontext.DataItem - Drag-and-Drop (
AllowDragRows,AllowedDropTarget,ItemsDropped): Row reordering within the same grid or moving rows between grids; requiresObservableCollection<T>for automatic UI refresh
Core Entry Point (Razor)
@rendermode InteractiveServer
<DxGrid Data="@Items" KeyFieldName="Id">
<Columns>
<DxGridCommandColumn />
<DxGridDataColumn FieldName="Name" />
<DxGridDataColumn FieldName="Date" DisplayFormat="d" />
</Columns>
</DxGrid>
Documentation & Navigation Guide
Getting Started
📄 references/getting-started.md
When you need to:
- Set up the Grid from scratch in a new or existing Blazor project
- Create your first grid with columns and data binding
- Enable interactive render mode for the grid page
Data Binding
When you need to:
- Bind to an in-memory list,
IQueryable, EF Core DbSet - Use
EntityInstantFeedbackSourceorEntityServerModeSourcefor large datasets - Configure a
GridCustomDataSourcefor Web API / OData backends - Understand which features are available per data-binding mode
Columns & Templates
📄 references/columns-and-templates.md
When you need to:
- Add, configure, or hide columns (
FieldName,Caption,Width,Visible) - Customize cell display or edit templates (
CellDisplayTemplate,CellEditTemplate) - Add a command column (New / Edit / Delete buttons)
- Create unbound columns with
UnboundExpression - Use band (header) columns to group related columns
Editing & Validation
📄 references/editing-and-validation.md
When you need to:
- Enable row editing in EditRow, EditForm, PopupEditForm, or EditCell mode
- Handle
EditModelSavingandDataItemDeletingevents - Customize the edit form using
EditFormTemplate - Validate user input with data annotations
Data Shaping
When you need to:
- Sort by one or multiple columns programmatically or in the UI
- Group rows and configure group summaries
- Add filter row, filter panel, search box, or column filter menu
- Show the filter panel or customize filter-builder operators for a specific field
- Create total and group summary items
Export
When you need to:
- Export grid data to CSV, XLS/XLSX, or PDF
- Customize exported cell styles, fonts, or document headers/footers
- Export only selected rows
Selection
When you need to:
- Enable single or multiple row selection
- Get/set
SelectedDataItemorSelectedDataItems - Add a
DxGridSelectionColumnwith checkboxes - Select rows programmatically using
SelectRow,SelectDataItem
Drag-and-Drop
When you need to:
- Enable row reordering within one grid (
AllowDragRows+AllowedDropTarget.Internal) - Move rows between two grids (
AllowedDropTarget.Externalon source,Allon target) - Handle
ItemsDroppedto updateObservableCollection<T>data sources - Use
GetTargetDataSourceIndexAsync()for simplified insertion-index calculation - Customize the drag hint with
DragHintTextTemplate
Examples
💻 examples/quickstart.razor — In-memory CRUD with EditRow, grouping, search box, summaries, and export
💻 examples/ef-core-crud.razor — Full EF Core CRUD with IDbContextFactory, async save/delete, and data reload
💻 examples/filter-panel-custom-date-operators.razor — FilterPanelDisplayMode with a custom Filter Builder that removes month operators for DueDate
💻 examples/custom-templates.razor — CellDisplayTemplate (badge rendering), EditFormTemplate with DxFormLayout, HeaderCaptionTemplate
💻 examples/drag-and-drop.razor — Row reordering within one grid and moving rows between two grids using ObservableCollection<T>
Quick Start Example
@page "/grid-demo"
@rendermode InteractiveServer
@inject WeatherForecastService ForecastService
<DxGrid @ref="Grid"
Data="@Forecasts"
KeyFieldName="Id"
EditMode="GridEditMode.EditRow"
EditModelSaving="OnEditModelSaving"
DataItemDeleting="OnDataItemDeleting"
ShowGroupPanel="true"
ShowSearchBox="true"
PageSize="10">
<Columns>
<DxGridCommandColumn />
<DxGridDataColumn FieldName="Date" DisplayFormat="d" SortOrder="GridColumnSortOrder.Ascending" SortIndex="0" />
<DxGridDataColumn FieldName="TemperatureC" Caption="Temp (°C)" />
<DxGridDataColumn FieldName="Forecast" />
<DxGridDataColumn FieldName="CloudCover" />
</Columns>
<TotalSummary>
<DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="Date" />
</TotalSummary>
</DxGrid>
@code {
IGrid Grid { get; set; }
List<WeatherForecast> Forecasts { get; set; }
protected override void OnInitialized() {
Forecasts = ForecastService.GetForecast();
}
void OnEditModelSaving(GridEditModelSavingEventArgs e) {
var model = (WeatherForecast)e.EditModel;
if (e.IsNew)
Forecasts.Add(model);
else
e.CopyChangesToDataItem();
Grid.Reload();
}
void OnDataItemDeleting(GridDataItemDeletingEventArgs e) {
Forecasts.Remove((WeatherForecast)e.DataItem);
Grid.Reload();
}
}
What This Does
Displays a weather forecast list with inline row editing, a delete button, sorting by date, a group panel, a search box, and a total count summary. Clicking the pencil icon opens editors inline; clicking delete prompts for removal.
Key Properties & API Surface
DxGrid
| Property / Method | Type | Description |
|---|---|---|
Data | object | Binds the grid to any supported data source |
KeyFieldName | string | Primary key field for editing and selection |
EditMode | GridEditMode | EditRow, EditForm, PopupEditForm, EditCell |
SelectionMode | GridSelectionMode | Single or Multiple |
SelectedDataItems | IReadOnlyList<object> | Currently selected data items (two-way bindable) |
PageSize | int | Rows per page (default 20) |
VirtualScrollingEnabled | bool | Set to true to enable virtual scrolling; false by default |
VirtualScrollingMode | GridVirtualScrollingMode | Rows (default — row virtualization only), Columns (column virtualization only), RowsAndColumns (both); ignored when VirtualScrollingEnabled is false |
ShowGroupPanel | bool | Show/hide the group panel |
ShowSearchBox | bool | Show/hide the search box |
AllowSort | bool | Enable/disable sorting globally |
ExportToCsvAsync() | Task | Export data to CSV |
ExportToXlsxAsync() | Task | Export data to XLS/XLSX |
ExportToPdfAsync() | Task | Export data to PDF |
Reload() | void | Refresh grid data — do not await |
BeginUpdate() / EndUpdate() | void | Batch parameter changes |
DetailRowTemplate | RenderFragment<GridDetailRowTemplateContext> | Template for the expandable detail row; context.DataItem is the master row's data item |
DetailRowDisplayMode | GridDetailRowDisplayMode | Auto (default — expandable detail rows; users expand/collapse), Never (detail rows hidden), Always (detail rows always shown as preview strips; cannot be collapsed) |
AutoCollapseDetailRow | bool | Collapse the previously expanded detail row when another is expanded |
ExpandDetailRow(int) | void | Expand the detail row at the specified visible row index |
CollapseDetailRow(int) | void | Collapse the detail row at the specified visible row index |
CollapseAllDetailRows() | void | Collapse all expanded detail rows |
IsDetailRowExpanded(int) | bool | Returns true if the detail row at the specified index is expanded |
AllowDragRows | bool | Allows users to start drag-and-drop row operations |
AllowedDropTarget | GridAllowedDropTarget | Controls where rows dragged FROM this grid can land. None — cannot reorder or drop onto other components; Internal (default) — rows can be reordered within this grid only; External — rows can be dropped onto other components (not reordered internally); All — rows can be reordered within this grid AND dropped onto other components |
ItemsDropped | EventCallback<GridItemsDroppedEventArgs> | Fires when rows are dropped onto this grid; update the data source here |
DropTargetMode | GridDropTargetMode | BetweenRows (default) — drop between rows; Component — drop onto the grid as a whole |
DragHintTextTemplate | RenderFragment<GridDragHintTextTemplateContext> | Custom drag hint displayed while dragging |
DxGridDataColumn
| Property | Type | Description |
|---|---|---|
FieldName | string | Data source field to bind the column to |
Caption | string | Column header text |
Width | string | Column width (e.g., "150px", "20%") |
DisplayFormat | string | Format string for display values |
SortOrder | GridColumnSortOrder | Ascending or Descending |
SortIndex | int | Order of this column in multi-column sort |
AllowSort | bool | Allow user sorting for this column |
AllowGroup | bool | Allow grouping by this column |
AllowFilter | bool | Allow column filter menu |
UnboundExpression | string | Expression for calculated unbound columns |
GroupInterval | GridColumnGroupInterval | Date/number interval for grouped values |
GridEditModelSavingEventArgs
| Member | Type | Description |
|---|---|---|
EditModel | object | The edit model (a copy of the data item) — cast to your type |
DataItem | object | The original data item (null when IsNew is true) |
IsNew | bool | true when a new row is being created |
CopyChangesToDataItem() | void | Copies edit model changes to the original data item |
Reload | bool | Set to true to reload grid data after the handler completes — use instead of Grid.Reload() when no @ref is held |
GridDataItemDeletingEventArgs
| Member | Type | Description |
|---|---|---|
DataItem | object | The data item to delete — cast to your type |
Reload | bool | Set to true to reload grid data after the handler completes — use instead of Grid.Reload() when no @ref is held |
GridDetailRowTemplateContext
| Member | Type | Description |
|---|---|---|
DataItem | object | The master row's data item — cast to your model type to pass as a parameter to the detail component |
GridItemsDroppedEventArgs
| Member | Type | Description |
|---|---|---|
DroppedItems | IReadOnlyList<object> | The data items that were dragged — cast each to your model type |
TargetItem | object | The row near which the drop occurred; null if dropped at the end of the list |
TargetItemVisibleIndex | int | The visible row index of TargetItem |
DropPosition | GridItemDropPosition | Before or After relative to TargetItem |
Grid | IGrid | The target grid that received the drop |
SourceComponent | object | The component that the rows originated from; cast to IGrid for grid-to-grid scenarios |
GetTargetDataSourceIndexAsync() | Task<int> | Returns the zero-based index in the data source where the dropped items should be inserted |
Common Patterns
Pattern 1: Editing with EF Core
<DxGrid Data="@Employees"
KeyFieldName="EmployeeId"
EditMode="GridEditMode.EditForm"
CustomizeEditModel="OnCustomizeEditModel"
EditModelSaving="OnEditModelSaving"
DataItemDeleting="OnDataItemDeleting">
<Columns>
<DxGridCommandColumn />
<DxGridDataColumn FieldName="FirstName" />
<DxGridDataColumn FieldName="LastName" />
<DxGridDataColumn FieldName="HireDate" />
</Columns>
<EditFormTemplate Context="editFormContext">
<DxFormLayout>
<DxFormLayoutItem Caption="First Name:">
@editFormContext.GetEditor("FirstName")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Last Name:">
@editFormContext.GetEditor("LastName")
</DxFormLayoutItem>
</DxFormLayout>
</EditFormTemplate>
</DxGrid>
@code {
IEnumerable<Employee> Employees { get; set; }
NorthwindContext Northwind { get; set; }
protected override async Task OnInitializedAsync() {
Northwind = NorthwindContextFactory.CreateDbContext();
Employees = await Northwind.Employees.ToListAsync();
}
void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e) {
if (e.IsNew)
((Employee)e.EditModel).EmployeeId = Employees.Max(x => x.EmployeeId) + 1;
}
async Task OnEditModelSaving(GridEditModelSavingEventArgs e) {
var model = (Employee)e.EditModel;
if (e.IsNew)
await Northwind.AddAsync(model);
else
e.CopyChangesToDataItem();
await Northwind.SaveChangesAsync();
Employees = await Northwind.Employees.ToListAsync();
}
async Task OnDataItemDeleting(GridDataItemDeletingEventArgs e) {
Northwind.Remove(e.DataItem);
await Northwind.SaveChangesAsync();
Employees = await Northwind.Employees.ToListAsync();
}
}
Pattern 2: Export to PDF via Toolbar
<DxGrid @ref="Grid" Data="@Items">
<Columns>
<DxGridDataColumn FieldName="Name" />
<DxGridDataColumn FieldName="Amount" />
</Columns>
<ToolbarTemplate>
<DxToolbar>
<DxToolbarItem Text="Export to PDF" Click="ExportPdf" />
</DxToolbar>
</ToolbarTemplate>
</DxGrid>
@code {
IGrid Grid;
async Task ExportPdf() {
await Grid.ExportToPdfAsync("report.pdf");
}
}
Pattern 3: Virtual Scrolling with In-Memory Data
Virtual scrolling requires VirtualScrollingEnabled="true". Use VirtualScrollingMode to choose between row-only (Rows, default) or row+column (RowsAndColumns) virtualization. Define Grid height via CSS — DxGrid has no Height property.
<DxGrid Data="@Items"
KeyFieldName="Id"
VirtualScrollingEnabled="true"
VirtualScrollingMode="GridVirtualScrollingMode.Rows"
CssClass="my-grid">
<Columns>
<DxGridDataColumn FieldName="Name" />
<DxGridDataColumn FieldName="Value" />
</Columns>
</DxGrid>
<style>
.my-grid {
height: 500px;
}
</style>
Note: When virtual scrolling is active,
PageSizehas no effect — all rows appear on a single page with a scrollbar.
Pattern 4: Master-Detail with Nested Grid
Master-detail uses DetailRowTemplate with a separate child component. The child receives the master row's data item as a [Parameter]. Always define the detail as a separate component — do not inline a second DxGrid directly inside the template in the same file.
@* MasterPage.razor — the master grid *@
@rendermode InteractiveServer
<DxGrid @ref="MasterGrid"
Data="@Customers"
KeyFieldName="Id"
AutoCollapseDetailRow="true">
<Columns>
<DxGridDataColumn FieldName="CompanyName" />
<DxGridDataColumn FieldName="Country" />
</Columns>
<DetailRowTemplate>
<CustomerOrdersDetail Customer="(Customer)context.DataItem" />
</DetailRowTemplate>
</DxGrid>
@code {
IGrid MasterGrid { get; set; }
List<Customer> Customers { get; set; }
protected override void OnInitialized() {
Customers = CustomerService.GetCustomers();
}
}
@* CustomerOrdersDetail.razor — the detail component *@
@rendermode InteractiveServer
<DxGrid Data="@Orders" KeyFieldName="OrderId" PageSize="5">
<Columns>
<DxGridDataColumn FieldName="OrderId" />
<DxGridDataColumn FieldName="OrderDate" DisplayFormat="d" />
<DxGridDataColumn FieldName="Amount" DisplayFormat="c" />
</Columns>
</DxGrid>
@code {
[Parameter]
public Customer Customer { get; set; }
List<Order> Orders { get; set; }
protected override void OnInitialized() {
Orders = OrderService.GetOrdersForCustomer(Customer.Id);
}
}
Key rules:
context.DataIteminDetailRowTemplateis the master row's object — cast it to pass as a parameter. Always define the nested grid in a separate.razorfile; inlining it directly causes render mode and lifecycle issues.
Pattern 5: Drag-and-Drop Row Reordering (Same Grid)
Use AllowDragRows="true" and AllowedDropTarget="GridAllowedDropTarget.Internal". The data source must be an ObservableCollection<T> so the grid reflects insertions/removals automatically.
<DxGrid Data="@Items"
KeyFieldName="Id"
AllowDragRows="true"
AllowedDropTarget="GridAllowedDropTarget.Internal"
ItemsDropped="OnItemsDropped">
<Columns>
<DxGridDataColumn FieldName="Name" />
<DxGridDataColumn FieldName="Priority" />
</Columns>
</DxGrid>
@code {
ObservableCollection<MyItem> Items { get; set; }
protected override void OnInitialized() {
Items = new ObservableCollection<MyItem>(DataService.GetItems());
}
void OnItemsDropped(GridItemsDroppedEventArgs e) {
var dropped = (MyItem)e.DroppedItems[0];
Items.Remove(dropped);
var target = (MyItem)e.TargetItem;
var index = target != null
? Items.IndexOf(target) + (e.DropPosition == GridItemDropPosition.After ? 1 : 0)
: Items.Count;
Items.Insert(index, dropped);
}
}
Pattern 6: Drag-and-Drop Between Two Grids
The source grid sets AllowDragRows="true" + AllowedDropTarget="GridAllowedDropTarget.External" — this permits dragging rows out to other components but keeps internal reordering disabled. The target sets AllowedDropTarget="GridAllowedDropTarget.All" (allows its own rows to reorder AND be dragged to other components) and handles ItemsDropped. Use e.SourceComponent and e.Grid to identify which ObservableCollection<T> to update. When inserting multiple rows, use .Reverse() to preserve their original order.
@* Source grid: rows can be dragged to external targets *@
<DxGrid @ref="SourceGrid"
Data="@SourceItems"
KeyFieldName="Id"
AllowDragRows="true"
AllowedDropTarget="GridAllowedDropTarget.External">
<Columns>
<DxGridDataColumn FieldName="Name" />
</Columns>
</DxGrid>
@* Target grid: allows internal reorder AND accepts external drops *@
<DxGrid Data="@TargetItems"
KeyFieldName="Id"
AllowDragRows="true"
AllowedDropTarget="GridAllowedDropTarget.All"
ItemsDropped="OnTargetItemsDropped">
<Columns>
<DxGridDataColumn FieldName="Name" />
</Columns>
</DxGrid>
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 53
- Forks
- 8
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
devexpress-blazor-grid- Source
- github.com/devexpress/agent-skills