When the Grid is grouped and aggregate functions are enabled, paging performance degrades significantly because grouping and aggregate calculations are executed on every page change. This results in noticeable delays and UI stutter, especially in WebAssembly applications and larger datasets.
This enhancement optimizes page navigation for grouped Grid scenarios with aggregates by avoiding repeated processing when the underlying data has not changed, resulting in substantially faster paging performance while preserving existing functionality and first-load behavior.
Hi,
The ask is for a feature request to take the already wonderfully done globally applied filter features down to a per column basis without the overhead and burden of resorting to the custom FilterMenuTemplate approach.
The current way of doing business creates much overhead in code particularly when several columns are involved.
Something like:
<TelerikGrid Data="@MyData"
FilterMode="@GridFilterMode.PerColumn"
<GridColumns>
<GridColumn Field="MyField01" FilterMode="@GridFilterColumnMode.FilterRow" />
<GridColumn Field="MyField02" FilterMode="@GridFilterColumnMode.FilterMenu" />
<GridColumn Field="MyField03" Filterable="false"/>
etc..
</GridColumns>
</TelerikGrid>
Thanks!
Ron
If LoadGroupsOnDemand="false", I am able to programmatically expand the groups through the state. However, this is not possible when loading group data on demand.
Please allow programmatically expanding the groups when LoadGroupsOnDemand="true". This should go together with an event (OnStateChanged?) that will fire when LOD groups are expanded or collapsed.
Title: Add per-column value converters (WPF-style) to Telerik Blazor Grid columns
Product: UI for Blazor → Grid
Type: Feature Request
Description:
In Telerik UI for WPF, grid column definitions can reference a converter by name (e.g., IValueConverter) to transform values for display without writing a custom cell template for each column.
In Telerik UI for Blazor Grid, templates are currently the primary way to change how values render in a column (which works, but becomes repetitive across many columns/grids).
Request:
Add a column-level conversion API that allows specifying a converter/formatter function for display (and optionally editing). Example concepts:
Converter="nameof(MyConverters.StatusToText)"
or DisplayConverter="(item) => …" / ValueFormatter="Func<TItem, object, string>"
optionally ConvertBack-like support for editing scenarios (or separate EditConverter)
Why this is needed:
Reduces repeated <Template> markup for simple formatting/transformations
Centralizes formatting/conversion logic in reusable code
Improves maintainability and consistency across grids
Eases migration for teams coming from Telerik WPF where converters are a common pattern
Use cases:
Enum/int → user-friendly text
Boolean → “Yes/No”, icons, badges
Null/empty → placeholder text
Code → display name (via lookup)
Domain-specific formatting shared across many grids
Workarounds today:
Column <Template> or computed properties (both valid, but not as concise/reusable for large grids)
Extracting RenderFragments can reduce repetition, but still requires templating infrastructure for what is logically a simple conversion step
Expected behavior:
Converter applies consistently anywhere the column renders (cell, export if applicable, etc.)
Works with sorting/filtering in a predictable way (ideally sorting/filtering still uses raw field value unless explicitly configured)
Hi,
I would like to have a Expand/Collapse All Grid Groups button in the Grid Header. I know this is possible to do so programmatically outside of the grid but my users want it inside the Grid.
Thanks,
Humayoon
The following KB article shows a workaround for removing the Grid aggregate labels ("Sum" and "Count") from the exported Excel document: https://www.telerik.com/blazor-ui/documentation/knowledge-base/grid-remove-aggregate-labels-in-excel-footr
It would be nice to have this option as a parameter in the Grid. It would allow to toggle on/off this behavior, instead of having to rely on custom code to work around it.
Or in the OnBeforeExport method, add extra data to GridBeforeExcelExportEventArgs that contains the aggregates so they can be changed.
private async Task OnBeforeExcelExport(GridBeforeExcelExportEventArgs args)
{
await Task.CompletedTask;
// Loop through all columns and fix the footer aggregate values
// Replace the default "Sum: 1234.56" text with just the decimal number
foreach (var column in args.Columns)
{
if (column.HasAggregate)
{
// Set the number format for the column so Excel treats it as a number
column.Aggregate.Field.Value == "MyNewValue";
}
}
}The Grid's CheckBoxColumn doesn't support the TextAlign property, making it impossible to center the checkbox with just Grid markup, you have to resort to a workaround.
The TextAlign property in other columns causes style="text-align: center" to be added to the underlying table cell. This would also work for the checkbox column.
See this test:
<table class="table">
<tr>
<td class="table-active" style="width: 40px; text-align: center"><input type="checkbox" /> </td>
<td>test</td>
</tr>
</table>Please add the TextAlign property to the CheckboxColumn.
I want to reorder the Grid rows the same way I can reorder the columns - via the keyboard.
For reference: Telerik jQuery Grid drag and drop
1. User clicks the sparkled button that opens the AI window in this demo: https://demos.telerik.com/blazor-ui/grid/ai-data-operations
2. User chooses a predefined prompt suggestion, enters one via the keyboard, or uses voice access to dictate one, and clicks apply. The operation runs successfully and returns output.
3. Now the user clicks the sparkled button again, and the AI window opens. Once open, the prompt text box fills with the previously entered request text.
How to remove or prevent the previously entered request text from filling the text box on every sequential opening of the AI window?
Please add support for programmatic exporting of Grids (SaveAsExcelFileAsync() and ExportToExcelAsync() ) with a GridExcelExportOptions argument and multi-column headers.
===
A potential workaround is to programmatically click the built-in export command button, which can even be hidden:
@using Telerik.Blazor.Components.Grid
@inject IJSRuntime JS
<PageTitle>Home</PageTitle>
<TelerikGrid Data="@GridData">
<GridToolBarTemplate>
<TelerikButton OnClick="@ExportGridWithOtherColumns">Export Programmatically</TelerikButton>
<GridCommandButton Class="hidden-export-button" Command="ExcelExport">Export Natively</GridCommandButton>
</GridToolBarTemplate>
<GridSettings>
<GridExcelExport OnBeforeExport="@OnGridBeforeExport" />
</GridSettings>
<GridColumns>
<GridColumn Field="@nameof(Product.Id)" Width="100px" />
<GridColumn Field="@nameof(Product.Name)" Width="120px" />
<GridColumn Title="Product Details">
<Columns>
<GridColumn Field="@nameof(Product.Group)" Width="180px" />
<GridColumn Field="@nameof(Product.Price)" DisplayFormat="{0:c2}" Width="120px" />
<GridColumn Field="@nameof(Product.Quantity)" DisplayFormat="{0:n0}" Width="120px" />
<GridColumn Field="@nameof(Product.Released)" DisplayFormat="{0:d}" Width="180px" />
<GridColumn Field="@nameof(Product.Discontinued)" Width="100px" />
</Columns>
</GridColumn>
</GridColumns>
</TelerikGrid>
<style>
.hidden-export-button {
display: none;
}
</style>
<script suppress-error="BL9992">
function clickExportCommandButton() {
let hiddenExportButton = document.querySelector(".hidden-export-button");
if (hiddenExportButton) {
hiddenExportButton.click();
}
}
</script>
@code {
private List<Product> GridData { get; set; } = new();
private void OnGridBeforeExport(GridBeforeExcelExportEventArgs args)
{
List<string> exportableColumnFields = new List<string> { nameof(Product.Name), nameof(Product.Price), nameof(Product.Quantity) };
List<GridExcelExportColumn> ColumnsToExport = new();
foreach (GridExcelExportColumn column in args.Columns)
{
if (exportableColumnFields.Contains(column.Field))
{
ColumnsToExport.Add(column);
}
}
args.Columns = ColumnsToExport;
}
private async Task ExportGridWithOtherColumns()
{
await JS.InvokeVoidAsync("clickExportCommandButton");
}
protected override void OnInitialized()
{
var rnd = Random.Shared;
for (int i = 1; i <= 7; i++)
{
GridData.Add(new Product()
{
Id = i,
Name = $"Name {i} {(char)rnd.Next(65, 91)}{(char)rnd.Next(65, 91)}",
Group = $"Group {i % 3 + 1}",
Price = rnd.Next(1, 100) * 1.23m,
Quantity = rnd.Next(0, 10000),
Released = DateTime.Today.AddDays(-rnd.Next(60, 1000)),
Discontinued = i % 4 == 0
});
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Group { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
public DateTime Released { get; set; }
public bool Discontinued { get; set; }
}
}