SamovarGrid 10.2.0
dotnet add package SamovarGrid --version 10.2.0
NuGet\Install-Package SamovarGrid -Version 10.2.0
<PackageReference Include="SamovarGrid" Version="10.2.0" />
<PackageVersion Include="SamovarGrid" Version="10.2.0" />
<PackageReference Include="SamovarGrid" />
paket add SamovarGrid --version 10.2.0
#r "nuget: SamovarGrid, 10.2.0"
#:package SamovarGrid@10.2.0
#addin nuget:?package=SamovarGrid&version=10.2.0
#tool nuget:?package=SamovarGrid&version=10.2.0
SamovarGrid
A full-featured data grid component for Blazor (.NET 10).
Features
- Paging and virtual scrolling
- Sorting
- Filtering — filter row, filter menu, or custom programmatic filter
- Inline and popup editing with built-in and custom edit templates
- Row insertion and deletion
- Single and multiple row selection
- Column resizing (block and sliding modes)
- Cell display templates
- Detail (expandable) rows
- Auto-generated columns from model properties
- Command bar with bulk selection, delete, and data export (Excel / CSV)
- Cell content alignment (left, center, right)
- Grid size modes (default, small, large)
- Column display format (standard .NET format strings)
- Expression columns (calculated values from field expressions)
- Globalization — 39 built-in languages, culture-reactive UI
- Custom localization — add languages or override individual strings
- CSS customization via Bootstrap classes and CSS custom properties
- Works with Interactive Server, WebAssembly, and Auto render modes
Getting Started
1. Install the NuGet package
dotnet add package SamovarGrid
2. Register services
// Program.cs
builder.Services.AddSamovarGrid();
3. Add the stylesheet
Option A — Automatic CSS injection (recommended)
// Program.cs
builder.Services.AddSamovarGrid(options => options.InjectCss = true);
@* App.razor *@
<head>
...
<SamovarGridStyles />
</head>
Option B — Manual link
<link href="_content/SamovarGrid/samovar.grid.css" rel="stylesheet" />
4. Add the using directive
@* _Imports.razor *@
@using Samovar.Grid
Basic Usage
@page "/"
@rendermode InteractiveServer
@inject EmployeeService EmployeeService
<SmGrid Data=employees Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
<Column Field="@nameof(Employee.Department)" />
<Column Field="@nameof(Employee.HireDate)" />
<Column Field="@nameof(Employee.Salary)" TextAlign="GridTextAlign.Right" />
</Columns>
</SmGrid>
@code {
private List<Employee>? employees;
protected override async Task OnInitializedAsync()
{
employees = (await EmployeeService.GetEmployeesAsync()).ToList();
}
}
Auto-Generated Columns
Set AutoGenerateColumns=true to let the grid reflect over the data model and generate columns for all public properties with simple types (string, int, DateTime, bool, decimal, etc.):
<SmGrid Data=employees AutoGenerateColumns=true />
Use [Browsable(false)] to exclude a property. Use [DisplayName] or [Display(Name=...)] to customize column headers:
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public class Employee
{
[DisplayName("Full Name")]
public string Name { get; set; }
[Display(Name = "Annual Salary")]
public decimal Salary { get; set; }
[Browsable(false)]
public string InternalId { get; set; }
}
Filtering
The grid supports four filter modes:
<SmGrid Data=employees FilterMode=GridFilterMode.FilterRow Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
<Column Field="@nameof(Employee.IsActive)" />
</Columns>
</SmGrid>
| Mode | Description |
|---|---|
GridFilterMode.None |
No filtering |
GridFilterMode.FilterRow |
Per-column filter inputs in a dedicated row |
GridFilterMode.FilterMenu |
Dropdown filter menus with value selection per column |
GridFilterMode.Custom |
Programmatic filter via ApplyCustomFilter() / ResetCustomFilter() |
Custom filter example:
async Task ApplyCustomFilter()
{
Func<Employee, bool> filter = e => e.IsActive;
await grid!.ApplyCustomFilter(filter);
}
async Task ResetCustomFilter()
{
await grid!.ResetCustomFilter();
}
Editing
Enable inline or popup editing with the EditMode parameter. Add a CommandColumn to display edit/insert/delete buttons:
<SmGrid Data=employees
EditMode=GridEditMode.Popup
RowEditBegin="@((Employee e) => { })"
RowInserting="@((Employee e) => { employees.Insert(0, e); })"
RowsRemoving="@((List<Employee> items) => { employees = employees.Except(items).ToList(); })"
Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
<Column Field="@nameof(Employee.Salary)" />
<CommandColumn EditButtonVisible=true DeleteButtonVisible=true NewButtonVisible=true Width="150px" />
</Columns>
</SmGrid>
| Mode | Description |
|---|---|
GridEditMode.None |
No editing |
GridEditMode.Form |
Edit form renders below the row |
GridEditMode.Popup |
Edit form in a modal popup |
Custom Edit / Insert Templates
For full control over the edit form, use EditFormTemplate and InsertFormTemplate:
<SmGrid Data=employees EditMode=GridEditMode.Form Height="600px">
<Columns>
<CommandColumn EditButtonVisible=true NewButtonVisible=true Width="150px" />
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.Salary)" />
</Columns>
<EditFormTemplate>
<EditForm Model="@editContext" OnValidSubmit="HandleEditSubmit">
<DataAnnotationsValidator />
<InputText @bind-Value="editContext.FirstName" />
<button type="submit">Save</button>
<button type="button" @onclick="() => grid.CancelCustomRowEdit(editContext)">Cancel</button>
</EditForm>
</EditFormTemplate>
</SmGrid>
Row Selection
<SmGrid Data=employees
SelectionMode=RowSelectionMode.Multiple
@bind-MultipleSelectedDataRows=selectedRows
Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
</Columns>
</SmGrid>
@code {
IEnumerable<Employee> selectedRows = [];
}
| Mode | Description |
|---|---|
RowSelectionMode.None |
No selection |
RowSelectionMode.Single |
One row at a time (bind with @bind-SingleSelectedDataRow) |
RowSelectionMode.Multiple |
Multiple rows with checkboxes (bind with @bind-MultipleSelectedDataRows) |
Command Bar
Enable the command bar for bulk actions and data export:
<SmGrid Data=employees
ShowCommandBar=true
SelectionMode=RowSelectionMode.Multiple
Height="600px">
...
</SmGrid>
The command bar provides:
- Select current page / Select all filtered rows / Deselect all buttons
- Delete selected rows
- Export dropdown: Excel (all / selected), CSV (all / selected)
Cell Templates
Customize how individual cells render:
<Column Field="@nameof(Employee.Salary)">
<CellShowTemplate>
@{
var salary = (context as Employee)!.Salary;
<span class="@(salary > 100000 ? "text-success fw-bold" : "")">
@salary.ToString("C")
</span>
}
</CellShowTemplate>
</Column>
Detail Rows
Expandable detail rows below each data row:
<SmGrid Data=employees ShowDetailRow=true Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
</Columns>
<DetailRowTemplate Context="item">
@{
var employee = item as Employee;
<div>Email: @employee!.Email</div>
<div>Phone: @employee.Phone</div>
}
</DetailRowTemplate>
</SmGrid>
Collapse all detail rows programmatically: await grid.CollapseAllDetailRows();
Virtual Scrolling
For large datasets, use virtual scrolling instead of paging:
<SmGrid Data=employees DataNavigationMode=NavigationMode.Virtual>
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.LastName)" />
</Columns>
</SmGrid>
Column Resizing
<SmGrid Data=employees ColumnResizeMode=GridColumnResizeMode.Sliding Height="600px">
...
</SmGrid>
| Mode | Description |
|---|---|
GridColumnResizeMode.None |
No resizing |
GridColumnResizeMode.Sliding |
Resize a column without affecting others |
GridColumnResizeMode.Block |
Resize a column, adjacent columns adjust |
Styling
Bootstrap CSS classes
Apply any Bootstrap table classes via CssClass and PaginationCssClass:
<SmGrid Data=employees
CssClass="table-bordered table-sm table-striped"
PaginationCssClass="pagination-sm"
Height="600px">
...
</SmGrid>
Grid size modes
<SmGrid Data=employees SizeMode=GridSizeMode.Small Height="600px">
...
</SmGrid>
| Mode | Description |
|---|---|
GridSizeMode.Default |
Standard spacing |
GridSizeMode.Small |
Compact spacing |
GridSizeMode.Large |
Generous spacing |
CSS custom properties
Override these CSS variables to customize the grid appearance:
:root {
--sm-row-selected-bg: rgba(69, 46, 222, 0.5);
--sm-no-data-color: #999;
--sm-detail-icon-size: 16px;
--sm-scrollbar-size: 8px;
--sm-scrollbar-thumb-color: #888;
--sm-scrollbar-thumb-hover-color: #555;
--sm-scrollbar-thumb-active-color: #333;
--sm-scrollbar-track-color: #f1f1f1;
--sm-scrollbar-thumb-radius: 4px;
--sm-detail-row-expanded-icon: url('data:image/svg+xml;utf8,...');
--sm-detail-row-collapsed-icon: url('data:image/svg+xml;utf8,...');
}
Cell Content Alignment
<Column Field="@nameof(Employee.Salary)" TextAlign="GridTextAlign.Right" />
<Column Field="@nameof(Employee.FirstName)" TextAlign="GridTextAlign.Center" />
Column Display Format
Use the Format parameter to apply any standard .NET format string to IFormattable column values (numbers, dates, etc.). The format is culture-aware and respects CultureInfo.CurrentCulture.
<Column Field="@nameof(Employee.Salary)" Format="C2" TextAlign="GridTextAlign.Right" />
<Column Field="@nameof(Employee.HireDate)" Format="yyyy-MM-dd" />
<Column Field="@nameof(Employee.Score)" Format="N2" TextAlign="GridTextAlign.Right" />
Expression Columns
ExpressionColumn computes a value from a formula referencing other fields using bracket notation. Use it for calculated columns without adding a property to your model.
<SmGrid Data=employees Height="600px">
<Columns>
<Column Field="@nameof(Employee.FirstName)" />
<Column Field="@nameof(Employee.Salary)" Format="C2" TextAlign="GridTextAlign.Right" />
<ExpressionColumn Title="Annual" Formula="[Salary] * 12" Width="130px" Format="C2" />
<ExpressionColumn Title="Daily" Formula="[Salary] / 30" Width="130px" Format="C2" />
<ExpressionColumn Title="Adjusted" Formula="([Salary] - 500) / 2" Width="130px" Format="C2" />
</Columns>
</SmGrid>
Supported operators: +, -, *, /, ( ). Field references must match the exact property name wrapped in brackets (e.g., [Salary]). Constant expressions are also valid (e.g., 365 * 2).
Globalization and Localization
The grid UI (buttons, labels, filter menus, pager, etc.) is fully localized. 39 languages are built in — the grid automatically picks the language from CultureInfo.CurrentCulture.
Built-in languages include: English, German, French, Spanish, Italian, Portuguese (BR/PT), Dutch, Russian, Ukrainian, Polish, Czech, Japanese, Chinese (Simplified/Traditional), Arabic, Hebrew, and many more.
To switch the grid language programmatically, inject ISamovarGridLocalizationService and call SetCulture:
@inject ISamovarGridLocalizationService L10n
void SwitchToGerman()
{
L10n.SetCulture(new CultureInfo("de-DE"));
}
Custom Localization
Add a new language (full dictionary):
// Program.cs
builder.Services.AddSamovarGrid(options =>
options.AddLanguage(
new CultureInfo("pt-BR"),
new Dictionary<string, string>
{
["Grid.Edit.Cancel"] = "Cancelar",
["Grid.Edit.Update"] = "Atualizar",
["Grid.Edit.Add"] = "Adicionar",
["Grid.Filter.Apply"] = "Aplicar",
["Grid.Filter.Cancel"] = "Cancelar",
["Grid.Common.NoData"] = "Sem dados",
// ... remaining keys
}
)
);
Override individual strings in an existing language:
builder.Services.AddSamovarGrid(options =>
{
options.OverrideString(new CultureInfo("en-GB"), "Grid.Common.NoData", "No records found");
options.OverrideString(new CultureInfo("de-DE"), "Grid.Edit.Cancel", "Abbrechen");
});
Custom strings take precedence over built-in resources. Partial overrides are supported — missing keys fall back to built-in translations.
<details> <summary>All localization key names</summary>
| Key | Default (en-GB) |
|---|---|
Grid.Edit.Cancel |
Cancel |
Grid.Edit.Update |
Update |
Grid.Edit.Add |
Add |
Grid.Edit.PopupTitle.Edit |
Edit |
Grid.Edit.PopupTitle.New |
New |
Grid.Edit.Close.AriaLabel |
Close |
Grid.Pager.PageOf |
Page {0} of {1} |
Grid.Pager.PreviousGlyph |
‹ |
Grid.Pager.NextGlyph |
› |
Grid.Filter.Values.Title |
Filter |
Grid.Filter.Search.Placeholder |
Search… |
Grid.Filter.SelectAll |
Select all |
Grid.Filter.Blank |
(Blank) |
Grid.Filter.Cancel |
Cancel |
Grid.Filter.Apply |
Apply |
Grid.Common.NoData |
No data |
Grid.CommandBar.SelectCurrentPage |
Select current page |
Grid.CommandBar.SelectAllFiltered |
Select all filtered |
Grid.CommandBar.DeselectAll |
Deselect all |
Grid.CommandBar.DeleteSelected |
Delete selected |
Grid.CommandBar.ExportExcelAll |
Export Excel (all) |
Grid.CommandBar.ExportExcelSelected |
Export Excel (selected) |
Grid.CommandBar.ExportCsvAll |
Export CSV (all) |
Grid.CommandBar.ExportCsvSelected |
Export CSV (selected) |
</details>
SmGrid Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
Data |
IEnumerable<T> |
— | Data source |
Height |
string |
— | Grid height (CSS value) |
Width |
string |
— | Grid width (CSS value) |
PageSize |
uint |
50 |
Rows per page |
PagerSize |
uint |
10 |
Pagination button count |
DataNavigationMode |
NavigationMode |
Paging |
Paging or Virtual |
FilterMode |
GridFilterMode |
None |
Filter mode |
EditMode |
GridEditMode |
None |
Edit mode |
SelectionMode |
RowSelectionMode |
None |
Row selection mode |
ColumnResizeMode |
GridColumnResizeMode |
None |
Column resize behavior |
SizeMode |
GridSizeMode |
Default |
Grid density |
CssClass |
string |
— | Bootstrap table classes |
PaginationCssClass |
string |
— | Bootstrap pagination classes |
ShowColumnHeader |
bool? |
true |
Show/hide column headers |
ShowDetailRow |
bool? |
false |
Enable detail rows |
ShowCommandBar |
bool |
false |
Show command bar |
AutoGenerateColumns |
bool |
false |
Auto-generate columns from model |
SingleSelectedDataRow |
T? |
— | Selected row (single mode) |
MultipleSelectedDataRows |
IEnumerable<T>? |
— | Selected rows (multiple mode) |
Column Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
Field |
string |
— | Property name from data model |
Title |
string? |
Field name | Column header text |
Width |
string? |
— | Column width (px, %, or flex like "1*") |
TextAlign |
GridTextAlign |
Left |
Cell content alignment |
Format |
string? |
— | .NET format string for IFormattable values (e.g. "C2", "yyyy-MM-dd") |
Resizable |
bool |
true |
Allow user resizing |
MinWidth |
double |
50 |
Minimum column width in px |
ExpressionColumn Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
Formula |
string |
— | Expression string (e.g. "[Salary] * 12") |
Title |
string? |
— | Column header text |
Width |
string? |
— | Column width (px, %, or flex like "1*") |
TextAlign |
GridTextAlign |
Right |
Cell content alignment |
Format |
string? |
— | .NET format string (e.g. "C2") |
Resizable |
bool |
true |
Allow user resizing |
MinWidth |
double |
50 |
Minimum column width in px |
CommandColumn Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
Width |
string |
— | Column width |
EditButtonVisible |
bool? |
true |
Show edit button |
NewButtonVisible |
bool? |
true |
Show insert button |
DeleteButtonVisible |
bool? |
true |
Show delete button |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ClosedXML (>= 0.105.0)
- Microsoft.AspNetCore.Components.Web (>= 10.0.6)
- Microsoft.Extensions.Localization (>= 10.0.6)
- System.Reactive (>= 6.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.