AtharvaITS.QuickGrid.Extensions
1.2.0
dotnet add package AtharvaITS.QuickGrid.Extensions --version 1.2.0
NuGet\Install-Package AtharvaITS.QuickGrid.Extensions -Version 1.2.0
<PackageReference Include="AtharvaITS.QuickGrid.Extensions" Version="1.2.0" />
<PackageVersion Include="AtharvaITS.QuickGrid.Extensions" Version="1.2.0" />
<PackageReference Include="AtharvaITS.QuickGrid.Extensions" />
paket add AtharvaITS.QuickGrid.Extensions --version 1.2.0
#r "nuget: AtharvaITS.QuickGrid.Extensions, 1.2.0"
#:package AtharvaITS.QuickGrid.Extensions@1.2.0
#addin nuget:?package=AtharvaITS.QuickGrid.Extensions&version=1.2.0
#tool nuget:?package=AtharvaITS.QuickGrid.Extensions&version=1.2.0
AtharvaITS.QuickGrid.Extensions
A lightweight Razor Class Library that adds column resizing, drag-and-drop column reordering, a column chooser, CSV / Excel / PDF export, and state management to Microsoft's QuickGrid — without replacing it or changing how you define columns.
Features
- Column Resizing — drag the right edge of any header cell to resize it. Default resize keeps total table width stable by balancing with a neighboring visible column. Hold Shift while dragging to resize a single column independently (table width can expand/shrink).
- Column Reordering — drag any column header to reorder using SortableJS (bundled, no CDN required).
- Column Chooser — a "⚙ Columns" button above the grid opens a dropdown where users can show or hide individual columns. Hidden state is preserved across sort, filter, and page changes.
- Export — optional toolbar (Export sits right of Columns) for CSV, Excel, and PDF. Modes: Current Table view, All Data, Pages, Rows (with
ExportPaginationState). HelpersGridExcelExporter/GridPdfExportersimplify server-side bytes. - State Management — persist column widths, order, visibility, and sort state to
localStorageautomatically viaStorageKey, or save/restore to your own server usingGetPreference/LoadPreference. - Zero changes to your QuickGrid — wrap with
<QuickGridExtension>. Columns, sorting, pagination, and item providers work exactly as before. - Virtualization compatible — a
MutationObserverpreserves column order and hidden-column state for dynamically added rows whenVirtualize="true". - Re-render safe — column widths, order, and visibility are restored automatically after every QuickGrid re-render (sort, filter, data refresh).
Requirements
| .NET | 10.0 |
| Microsoft.AspNetCore.Components.QuickGrid | 10.x |
| Blazor hosting model | Server, WebAssembly, or Auto |
Installation
.NET CLI
dotnet add package AtharvaITS.QuickGrid.Extensions
NuGet Package Manager Console (Visual Studio)
Install-Package AtharvaITS.QuickGrid.Extensions
Package Reference (.csproj)
<PackageReference Include="AtharvaITS.QuickGrid.Extensions" Version="1.2.0" />
Setup
Add to _Imports.razor:
@using AtharvaITS.QuickGrid.Extensions.Components
@using AtharvaITS.QuickGrid.Extensions.Models
@using AtharvaITS.QuickGrid.Extensions.Exporting
The Models namespace contains QuickGridPreference, export types (GridExportRequest, GridExportResult, ExportFormat, etc.). The Exporting namespace contains GridExcelExporter and GridPdfExporter for building full-data .xlsx and .pdf files from row strings.
No changes to Program.cs are needed. Static assets are served automatically via _content/AtharvaITS.QuickGrid.Extensions/.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
ChildContent |
RenderFragment |
— | The <QuickGrid> to enhance. |
EnableResize |
bool |
true |
Allow columns to be resized by dragging the right edge of a header. |
EnableReorder |
bool |
true |
Allow columns to be reordered by dragging header cells. |
EnableColumnChooser |
bool |
true |
Show a "⚙ Columns" button above the grid that lets users toggle individual column visibility. Hidden state survives sort, filter, and page changes. |
ShowResetButton |
bool |
false |
Show a Reset button in the toolbar to restore default column order, widths, visibility, and sort preferences. |
MinColumnWidth |
int |
80 |
Minimum column width in pixels during resize. |
StorageKey |
string? |
null |
Unique key identifying this grid's preferences in localStorage. Multiple grids on the same page must use distinct values. When omitted, persistence is disabled entirely. |
StorageScope |
string? |
null |
Optional namespace prefix combined with StorageKey to isolate preferences per user, page, or tenant. Final key: eqg_pref_{StorageScope}_{StorageKey}. Examples: userId, $"{userId}/admin", $"{tenantId}/{userId}". |
AutoRestoreSort |
bool |
false |
When true, automatically restores the last active sort on page load by programmatically clicking the stored column header. Causes 1–2 extra data loads; best suited for in-memory IQueryable grids. For GridItemsProvider grids, use OnSortChanged instead. |
OnSortChanged |
EventCallback<QuickGridPreference> |
— | Raised whenever the active sort column or direction changes, and once on first render when a stored sort preference is found. Use SortColumnIndex and SortDirection from the snapshot to seed your GridItemsProvider. |
EnableExport |
bool |
false |
When true, shows an Export control (to the right of Columns) with CSV, Excel (.xlsx by default), and PDF options. |
DataLoadMode |
GridDataLoadMode |
InMemoryFullDom |
When Virtualized, Current Table view and Pages are hidden in the export panel. |
EnableExportCurrentView |
bool |
true |
Allow Current Table view (DOM export) unless DataLoadMode is Virtualized. |
EnableExportFullData |
bool |
true |
Allow All Data when OnExportRequested is set. |
AllowDomExportWhenVirtualized |
bool |
false |
Obsolete — kept for backward compatibility. |
ExportPaginationState |
PaginationState? |
null |
Recommended. Same PaginationState as the grid; page/row limits refresh when totals change. |
ExportPagination |
GridExportPaginationContext? |
null |
Manual snapshot for Pages and Rows. Requires host StateHasChanged when pagination changes unless you use ExportPaginationState. |
ExportFileNameBase |
string |
"export" |
Base download file name (no extension); invalid characters are stripped in JavaScript. |
IncludeUtf8BomInCsv |
bool |
true |
Prefix CSV with a UTF-8 BOM for Excel-friendly opening. |
ExportCurrentViewExcelAsSpreadsheetMl |
bool |
false |
When true, current-table Excel uses legacy Excel 2003 SpreadsheetML (.xml) instead of .xlsx. |
OnExportRequested |
Func<GridExportRequest, Task<GridExportResult?>>? |
null |
Required for All Data, Pages, and Rows exports. Receives column metadata, sort info, and ExportFormat. Return null to signal failure. |
Export scopes and data loading
| Scope | Meaning |
|---|---|
| Current Table view | Serializes the live DOM (visible columns and all <tbody> rows currently shown). Hidden when DataLoadMode="Virtualized". |
| All Data | Full dataset via OnExportRequested (ExportScope.FullData). |
| Pages | Shown when ExportPaginationState or ExportPagination is set and DataLoadMode is not Virtualized. Enter From page / To page (required). Server export with FromPage / ToPage on GridExportRequest. |
| Rows | Shown when ExportPaginationState or ExportPagination is set. Enter From row / To row (required, global 1-based). Server export with ExportScope.RowRange and FromRow / ToRow. |
Bind pagination for page-range export (recommended):
<QuickGridExtension ExportPaginationState="@_pagination" OnExportRequested="ExportAsync" ...>
<QuickGrid Pagination="@_pagination" ... />
</QuickGridExtension>
<Paginator State="@_pagination" />
Or build a snapshot manually (call StateHasChanged when PaginationState changes):
ExportPagination="@GridExportPaginationContext.From(_pagination)"
Excel note: Current-table Excel downloads a .xlsx file (Open XML) unless ExportCurrentViewExcelAsSpreadsheetMl is true (legacy .xml). For all rows, return bytes from OnExportRequested; you can build the workbook with GridExcelExporter.CreateXlsx (or ClosedXML, EPPlus, etc.).
PDF note: Current-view PDF opens a new window with a clean table and the browser Print dialog (user chooses “Save as PDF”). For all rows, return PDF bytes from your handler; GridPdfExporter.CreateSimpleTablePdf uses PDFsharp with an embedded Roboto font when no custom GlobalFontSettings.FontResolver is set, so it works on Blazor WebAssembly without extra setup.
Resize Behavior
- Default drag: adjusts the target column and a deterministic neighboring visible column (right-first, then left fallback) to keep table width stable.
- Shift + drag: resizes only the target column (independent mode). Use this when you want the table to grow or shrink horizontally.
- Hidden columns: when a column is hidden and later shown from the chooser, its previous width is restored.
Examples
1. Default — resize, reorder, and column chooser enabled
@using Microsoft.AspNetCore.Components.QuickGrid
<QuickGridExtension>
<QuickGrid Items="@_employees.AsQueryable()" TGridItem="Employee">
<PropertyColumn Property="@(e => e.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(e => e.Department)" Title="Department" Sortable="true" />
<PropertyColumn Property="@(e => e.Salary)" Title="Salary" Sortable="true" Format="C0" />
</QuickGrid>
</QuickGridExtension>
2. Column chooser only (disable resize and reorder)
<QuickGridExtension EnableResize="false" EnableReorder="false">
<QuickGrid Items="@_employees.AsQueryable()" TGridItem="Employee">
<PropertyColumn Property="@(e => e.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(e => e.Department)" Title="Department" Sortable="true" />
<PropertyColumn Property="@(e => e.Location)" Title="Location" />
<PropertyColumn Property="@(e => e.Salary)" Title="Salary" Sortable="true" Format="C0" />
</QuickGrid>
</QuickGridExtension>
2a. Enable the reset button in toolbar
<QuickGridExtension ShowResetButton="true" StorageKey="employees-grid">
<QuickGrid Items="@_employees.AsQueryable()" TGridItem="Employee">
<PropertyColumn Property="@(e => e.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(e => e.Department)" Title="Department" Sortable="true" />
<PropertyColumn Property="@(e => e.Location)" Title="Location" />
</QuickGrid>
</QuickGridExtension>
3. Resize only / Reorder only
@* Resize only — hide column chooser too *@
<QuickGridExtension EnableReorder="false" EnableColumnChooser="false" MinColumnWidth="120">
<QuickGrid Items="@_items.AsQueryable()" TGridItem="Product">
<PropertyColumn Property="@(p => p.Name)" Title="Product" />
<PropertyColumn Property="@(p => p.Price)" Title="Price" Format="C2" />
</QuickGrid>
</QuickGridExtension>
@* Reorder only — hide column chooser too *@
<QuickGridExtension EnableResize="false" EnableColumnChooser="false">
<QuickGrid Items="@_items.AsQueryable()" TGridItem="Product">
<PropertyColumn Property="@(p => p.Name)" Title="Product" />
<PropertyColumn Property="@(p => p.Category)" Title="Category" />
</QuickGrid>
</QuickGridExtension>
4. With virtualization and server-side data
<QuickGridExtension>
<QuickGrid TGridItem="Order" ItemsProvider="@_ordersProvider" Virtualize="true" ItemSize="40">
<PropertyColumn Property="@(o => o.OrderId)" Title="Order #" Sortable="true" />
<PropertyColumn Property="@(o => o.Customer)" Title="Customer" Sortable="true" />
<PropertyColumn Property="@(o => o.Total)" Title="Total" Sortable="true" Format="C2" />
<PropertyColumn Property="@(o => o.Status)" Title="Status" />
</QuickGrid>
</QuickGridExtension>
5. Blazor Server App with pagination
Note: The component requires an interactive render mode. Without it, the grid renders as a static table and resize/reorder will not work.
@page "/employees"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.QuickGrid
@inject IEmployeeService EmployeeService
<QuickGridExtension>
<QuickGrid Items="@_employees" TGridItem="Employee" Pagination="@_pagination">
<PropertyColumn Property="@(e => e.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(e => e.Department)" Title="Department" Sortable="true" />
<PropertyColumn Property="@(e => e.Location)" Title="Location" />
<PropertyColumn Property="@(e => e.Salary)" Title="Salary" Sortable="true" Format="C0" />
</QuickGrid>
</QuickGridExtension>
<Paginator State="@_pagination" />
@code {
private IQueryable<Employee> _employees = Enumerable.Empty<Employee>().AsQueryable();
private readonly PaginationState _pagination = new() { ItemsPerPage = 20 };
protected override async Task OnInitializedAsync()
{
_employees = (await EmployeeService.GetAllAsync()).AsQueryable();
}
}
6. localStorage auto-persistence with StorageKey and StorageScope
Column widths, order, visibility, and sort are automatically saved to localStorage and restored on the next page load. Use StorageScope to isolate preferences per user.
@page "/orders"
@rendermode InteractiveServer
@inject IHttpContextAccessor HttpContext
<QuickGridExtension StorageKey="orders-grid"
StorageScope="@_userId"
AutoRestoreSort="true">
<QuickGrid Items="@_orders.AsQueryable()" TGridItem="Order">
<PropertyColumn Property="@(o => o.OrderId)" Title="Order #" Sortable="true" />
<PropertyColumn Property="@(o => o.Customer)" Title="Customer" Sortable="true" />
<PropertyColumn Property="@(o => o.Total)" Title="Total" Sortable="true" Format="C2" />
<PropertyColumn Property="@(o => o.Status)" Title="Status" />
</QuickGrid>
</QuickGridExtension>
@code {
private List<Order> _orders = new();
private string? _userId;
protected override async Task OnInitializedAsync()
{
_userId = HttpContext.HttpContext?.User.FindFirst("sub")?.Value;
_orders = await OrderService.GetAllAsync();
}
}
7. Server-side sort restore using OnSortChanged and GridItemsProvider
For grids backed by a GridItemsProvider, use OnSortChanged to seed the sort state before data is fetched. This avoids the extra network requests that AutoRestoreSort would cause.
@page "/products"
@rendermode InteractiveServer
@using AtharvaITS.QuickGrid.Extensions.Models
<QuickGridExtension StorageKey="products-grid"
OnSortChanged="@HandleSortChanged">
<QuickGrid TGridItem="Product" ItemsProvider="@_provider">
<PropertyColumn Property="@(p => p.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(p => p.Category)" Title="Category" Sortable="true" />
<PropertyColumn Property="@(p => p.Price)" Title="Price" Sortable="true" Format="C2" />
<PropertyColumn Property="@(p => p.Stock)" Title="In Stock" Sortable="true" />
</QuickGrid>
</QuickGridExtension>
@code {
private GridItemsProvider<Product>? _provider;
private string _sortField = nameof(Product.Name);
private bool _sortAscending = true;
protected override void OnInitialized()
{
_provider = async req =>
{
var result = await ProductService.GetPagedAsync(_sortField, _sortAscending, req.StartIndex, req.Count ?? 20);
return GridItemsProviderResult.From(result.Items, result.TotalCount);
};
}
private Task HandleSortChanged(QuickGridPreference pref)
{
// Map the stored column index back to the sort field name.
_sortField = pref.SortColumnIndex switch
{
0 => nameof(Product.Name),
1 => nameof(Product.Category),
2 => nameof(Product.Price),
3 => nameof(Product.Stock),
_ => nameof(Product.Name)
};
_sortAscending = pref.SortDirection != "descending";
return Task.CompletedTask;
}
}
8. Export toolbar (CSV, Excel, PDF)
Set EnableExport="true". For all rows, assign OnExportRequested and set DataLoadMode when the grid uses virtualization or a GridItemsProvider. The example below uses GridExcelExporter and GridPdfExporter for full-data Excel and PDF.
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.QuickGrid
@using AtharvaITS.QuickGrid.Extensions.Models
@using AtharvaITS.QuickGrid.Extensions.Exporting
@using System.Text
<QuickGridExtension EnableExport="true"
StorageKey="employees-export"
DataLoadMode="GridDataLoadMode.InMemoryFullDom"
ExportFileNameBase="Employees"
OnExportRequested="@HandleExport">
<QuickGrid Items="@_employees.AsQueryable()" TGridItem="Employee">
<PropertyColumn Property="@(e => e.Name)" Title="Name" Sortable="true" />
<PropertyColumn Property="@(e => e.Department)" Title="Department" Sortable="true" />
</QuickGrid>
</QuickGridExtension>
@code {
private List<Employee> _employees = new();
private Task<GridExportResult?> HandleExport(GridExportRequest request)
{
var baseName = string.IsNullOrWhiteSpace(request.FileNameBase) ? "employees_full" : request.FileNameBase;
var rows = _employees.Select(e =>
(IReadOnlyList<string>)request.ColumnOriginalIndicesInDisplayOrder
.Select(i => CellFor(e, i)).ToList()).ToList();
switch (request.Format)
{
case ExportFormat.Csv:
{
var sb = new StringBuilder();
sb.AppendLine(string.Join(",", request.ColumnHeaders.Select(h => $"\"{h.Replace("\"", "\"\"")}\"")));
foreach (var line in rows)
sb.AppendLine(string.Join(",", line.Select(c => $"\"{c.Replace("\"", "\"\"")}\"")));
var bytes = Encoding.UTF8.GetBytes(sb.ToString());
return Task.FromResult<GridExportResult?>(new GridExportResult
{
Content = bytes,
ContentType = "text/csv; charset=utf-8",
FileName = $"{baseName}.csv"
});
}
case ExportFormat.ExcelXml:
{
var bytes = GridExcelExporter.CreateXlsx(request.ColumnHeaders, rows);
return Task.FromResult<GridExportResult?>(new GridExportResult
{
Content = bytes,
ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
FileName = $"{baseName}.xlsx"
});
}
case ExportFormat.Pdf:
{
var bytes = GridPdfExporter.CreateSimpleTablePdf(request.ColumnHeaders, rows, title: "Employees");
return Task.FromResult<GridExportResult?>(new GridExportResult
{
Content = bytes,
ContentType = "application/pdf",
FileName = $"{baseName}.pdf"
});
}
default:
return Task.FromResult<GridExportResult?>(null);
}
}
private static string CellFor(Employee e, int colIdx) => colIdx switch
{
0 => e.Name,
1 => e.Department,
_ => ""
};
}
For Virtualize="true" or ItemsProvider, set DataLoadMode="GridDataLoadMode.Virtualized" or ItemsProviderOrServerPaged and implement OnExportRequested to query the database (or call an export API) without relying on the DOM.
9. Programmatic save and restore to a database
Use GetPreference to capture the current layout and LoadPreference to restore a previously saved one from your own storage.
@page "/reports"
@rendermode InteractiveServer
@using AtharvaITS.QuickGrid.Extensions.Models
@inject IUserPreferenceService PreferenceService
@inject IHttpContextAccessor HttpContext
<button @onclick="SaveLayout">Save Layout</button>
<button @onclick="ResetLayout">Reset Layout</button>
<QuickGridExtension @ref="_grid">
<QuickGrid Items="@_reports.AsQueryable()" TGridItem="Report">
<PropertyColumn Property="@(r => r.Title)" Title="Title" Sortable="true" />
<PropertyColumn Property="@(r => r.Category)" Title="Category" Sortable="true" />
<PropertyColumn Property="@(r => r.Date)" Title="Date" Sortable="true" />
<PropertyColumn Property="@(r => r.Author)" Title="Author" />
</QuickGrid>
</QuickGridExtension>
@code {
private QuickGridExtension _grid = default!;
private List<Report> _reports = new();
private string? _userId;
protected override async Task OnInitializedAsync()
{
_userId = HttpContext.HttpContext?.User.FindFirst("sub")?.Value;
_reports = await ReportService.GetAllAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && _userId is not null)
{
var saved = await PreferenceService.LoadAsync(_userId, "reports-grid");
if (saved is not null)
await _grid.LoadPreference(saved);
}
}
private async Task SaveLayout()
{
var pref = _grid.GetPreference();
if (_userId is not null)
await PreferenceService.SaveAsync(_userId, "reports-grid", pref);
}
private async Task ResetLayout()
{
await _grid.ClearPreference();
}
}
State Management
localStorage Auto-Persistence
Set StorageKey to automatically save and restore column widths, order, visibility, and sort state across page loads. No additional code is required — the component reads from and writes to localStorage on every user interaction.
<QuickGridExtension StorageKey="my-grid">
...
</QuickGridExtension>
Use StorageScope to namespace preferences per user, page, or tenant so that multiple users sharing the same browser profile (or the same user across different tenants) do not overwrite each other's layouts:
<QuickGridExtension StorageKey="employees-grid" StorageScope="@userId">
...
</QuickGridExtension>
The final localStorage key is eqg_pref_{StorageScope}_{StorageKey} (or eqg_pref_{StorageKey} when StorageScope is omitted).
QuickGridPreference Model
QuickGridPreference (namespace AtharvaITS.QuickGrid.Extensions.Models) represents a complete snapshot of the grid's column layout. It is the type passed to OnSortChanged, returned by GetPreference, and accepted by LoadPreference.
| Property | Type | Description |
|---|---|---|
ColumnOrder |
int[]? |
Original column indices in their current visual positions. null means default order. |
ColumnWidths |
Dictionary<int, int>? |
Resized column widths in pixels, keyed by original column index. |
HiddenColumns |
int[]? |
Original indices of columns currently hidden. null or empty means all columns visible. |
SortColumnIndex |
int? |
Zero-based original index of the active sort column, or null when unsorted. |
SortDirection |
string? |
"ascending", "descending", or null when unsorted. |
Developer API Methods
These methods are available on the QuickGridExtension component reference (via @ref). They must be called after the component's first render (i.e., in or after OnAfterRenderAsync with firstRender = true).
| Method | Returns | Description |
|---|---|---|
GetPreference() |
QuickGridPreference |
Returns a snapshot of the current column layout — order, widths, visibility, and sort state. Use this to save the layout to your server or database. |
LoadPreference(QuickGridPreference) |
Task |
Applies a saved preference to the live DOM and updates internal Blazor state. If StorageKey is set, the next user interaction will also persist this preference to localStorage. |
ClearPreference() |
Task |
Removes the stored localStorage entry for this grid. The current in-memory layout is unchanged; the grid will start from its default layout on the next page load. No-op when StorageKey is not set. |
Sort Persistence
Two modes are available depending on your data source:
AutoRestoreSort="true" (in-memory grids)
The component programmatically clicks the stored column header to restore the sort. Zero developer code required. Note that ascending sorts cause one extra data load and descending sorts cause two, because QuickGrid requires two clicks to reach descending order. Best suited for in-memory IQueryable data sources.
<QuickGridExtension StorageKey="my-grid" AutoRestoreSort="true">
...
</QuickGridExtension>
OnSortChanged callback (GridItemsProvider grids)
For server-side grids, subscribe to OnSortChanged to receive the stored sort on first render and every subsequent user sort. Use SortColumnIndex and SortDirection from the QuickGridPreference snapshot to update your GridItemsProvider query without triggering extra network requests.
<QuickGridExtension StorageKey="my-grid" OnSortChanged="@HandleSortChanged">
...
</QuickGridExtension>
@code {
private Task HandleSortChanged(QuickGridPreference pref)
{
_sortField = MapIndexToField(pref.SortColumnIndex);
_sortAscending = pref.SortDirection != "descending";
return Task.CompletedTask;
}
}
How It Works
Column Resize: After QuickGrid renders, extendedQuickGrid.js injects a <colgroup> and appends a 5 px drag handle to each header cell. Default drag keeps overall table width stable by balancing with a visible neighboring column; holding Shift switches to independent single-column resize. Final widths are reported back to Blazor and restored after every re-render.
Column Reorder: SortableJS is initialised on thead > tr. A drag-handle icon (⠿) is prepended to each header so accidental drags on column text are avoided. On drop, <td> cells in every <tbody> row are reordered to match the new header order (single DOM write per row via DocumentFragment). The order is stored in Blazor state and re-applied after every re-render.
Column Chooser: A "⚙ Columns" toolbar is injected above the scrollable table area. Clicking it opens a dropdown listing every column with a checkbox. Toggling a checkbox collapses the corresponding <col> (via visibility: collapse and width management) and updates matching <th>/<td> visibility. Each visibility change is reported back to Blazor via OnColumnVisibilityChanged so the hidden-column set is restored on every re-render (sort, filter, page change). The MutationObserver that already handles virtualization also applies visibility to newly added rows for hidden columns. Hidden state is tracked by the original column index (data-col-idx), so it survives column reorders.
State Management: On first render, Blazor loads any stored QuickGridPreference from localStorage (when StorageKey is set) and passes it as the initial preference to initGrid, ensuring the correct layout is applied before the first paint. Subsequent user interactions (resize, reorder, visibility toggle, sort) update both the Blazor-side state and localStorage atomically. On every QuickGrid re-render, reinitGrid re-applies the current Blazor state to the DOM — making column layout fully transparent to QuickGrid's sort, filter, and pagination cycles.
Export: When EnableExport is true, Export appears to the right of Columns. Choose Current Table view, All Data, Pages, or Rows; page and row inputs appear only for the selected mode. Bind ExportPaginationState (recommended) or ExportPagination for Pages and Rows server exports.
SortableJS: The Sortable.min.js file (v1.15.7, SortableJS) is bundled inside the package and served from _content/AtharvaITS.QuickGrid.Extensions/js/. No CDN access or manual download is required.
Limitations
| Limitation | Detail |
|---|---|
| Persistence requires explicit opt-in | Set StorageKey for automatic localStorage persistence, or use GetPreference / LoadPreference to integrate with server-side storage. Without a StorageKey, column layout is in-memory only and is lost on page reload. |
| Reorder and visibility are DOM-level only | Blazor component state for column positions is not updated; only the rendered DOM changes. |
Fixed-width colgroup required |
The wrapper always injects a <colgroup>, switching the table to table-layout: fixed. Adjust MinColumnWidth or CSS if needed. |
| Column names in chooser come from header text | If a column header uses complex markup, the chooser reads the text content after stripping resize handles. Provide clear text in Title for best results. |
| Current-table export scope | Exports only rows present in the DOM. With Virtualize="true", ItemsProvider, or server-side pagination, that is usually a partial dataset unless every row is rendered. Use DataLoadMode and OnExportRequested for full exports. |
Links
🤝 Support
For support, feature requests, or bug reports:
- Website: https://www.atharvaits.com
- Email: contact@atharvaits.com
- Company: Atharva IT Services Pvt. Ltd.
📄 License
Copyright © 2026 Atharva IT Services Pvt. Ltd.
🏢 About Atharva IT Services
Atharva IT Services Pvt. Ltd. a global software development company in Ahmedabad, excels in e-commerce solutions, web development, and software testing.
Made with ❤️ by Atharva IT Services
| 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
- DocumentFormat.OpenXml (>= 3.5.1)
- Microsoft.AspNetCore.Components.QuickGrid (>= 10.0.7)
- Microsoft.AspNetCore.Components.Web (>= 10.0.7)
- PDFsharp (>= 6.2.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
# Release Notes
## v1.2.0
- Added **Export** toolbar for QuickGrid.
## v1.1.0
- Added Column Chooser: toggle individual column visibility via a "⚙ Columns" dropdown above the grid
- Added State Management: automatic localStorage persistence via StorageKey and StorageScope parameters
- Added QuickGridPreference model with GetPreference / LoadPreference / ClearPreference developer API
- Added sort persistence: AutoRestoreSort parameter and OnSortChanged event callback
- Added Shift-resize mode: hold Shift while dragging a resize handle to resize a single column independently
- Fixed column resize issue causing unexpected behavior
## v1.0.2
- Added README.md to NuGet package
## v1.0.1
- Fixed: column re-ordering did not preserve cell values in reordered columns
## v1.0.0
- Initial release with Column Resize and Column Re-Order functionality