Blazor Wasm Grid Performance

I'm having a lot of performance issues trying to implement the SfGrid component in my blazor wasm app.  I'm talking about trying to display ~20-50 records at a time with 4-10 columns and it is taking over 2 seconds to render.  I also am using the context menu and again it causes rendering issues and  takes about 2-6 seconds to open the context menu.  This is unacceptable for the speed and responsiveness of my application.


I am also using the grid on a server app and have had no issues with a nearly identical implementation.. Is there anyway you can provide a sample similar to my implentation that has better responsiveness?


My implementation looks something like this :


        <SfGrid ID=@($"CompactGrid_{_id}") @ref=@GridRef DataSource=@PaginationDto.Items TValue="TDto"
                ContextMenuItems=@_contextMenuItems Toolbar=@_toolbar
                ShowColumnChooser=@true ShouldRenderHiddenColumns=@false EnablePersistence=@true
                RowHeight=@(20) Width="100%" Height="100%" AllowResizing=@true AllowSelection=@false>

            <GridEvents TValue="TDto" ContextMenuOpen=@OpenSfContextMenu OnRecordDoubleClick=@SfDoubleClick OnRecordClick=@SfSingleClick />

            @if (WebDetailTemplate != null)
            {
                <GridTemplates>

                    <EmptyRecordTemplate>
                        @if (Loading)
                        {
                            <WebLoading Count=@(2) />
                        }
                    </EmptyRecordTemplate>

                    <DetailTemplate>
                        @WebDetailTemplate.Invoke((context as TDto)!)
                    </DetailTemplate>

                </GridTemplates>
            }
            else
            {
                <GridTemplates>
                    <EmptyRecordTemplate>
                        @if (Loading)
                        {
                            <WebLoading Count=@(2) />
                        }
                    </EmptyRecordTemplate>
                </GridTemplates>
            }

            <GridColumns>
                <GridColumn Width="50" MaxWidth="50" MinWidth="50" HeaderText="Menu" Visible=@true>
                    <Template>
                        @{
                            var item = (context as BaseDto)!;

                            <div class="row g-0 text-center">
                                <SfButton CssClass="e-small btn btn-sm btn-outline-dark p-0" IconCss="bi bi-three-dots" OnClick=@((args) => OpenWebContextMenu(args, item?.Id)) />
                            </div>
                        }
                    </Template>
                </GridColumn>
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.Id) HeaderText="Guid Id" IsPrimaryKey=@true Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.CreationDate) HeaderText="Creation Date" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.CreationIp) HeaderText="Creation IP" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.CreationUserName) HeaderText="Creation Person" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.ModificationDate) HeaderText="Modification Date" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.ModificationIp) HeaderText="Modification IP" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.ModificationUserName) HeaderText="Modification Person" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.ChangeKey) HeaderText="Change Key" Visible=@false />
                <GridColumn Width="150" MinWidth="150" ClipMode=@ClipMode.EllipsisWithTooltip Field=@nameof(BaseDto.Xmin) HeaderText="Xmin" Visible=@false />
            </GridColumns>
        </SfGrid>


    private Guid _id = Guid.CreateVersion7();
    private SfGrid<TDto>? GridRef;
    private List<ContextMenuItemModel> _contextMenuItems = new();
    private List<string>? _toolbar => new() { "ColumnChooser" };
    public async Task OpenSfContextMenu(ContextMenuOpenEventArgs<TDto> args)
    {
        args.Cancel = true;
        var cellValue = Syncfusion.Blazor.Data.DataUtil.GetObject(args?.Column?.Field ?? "", args?.RowInfo?.RowData ?? new object());
        WebContextMenuArgs menuArgs = new(args?.RowInfo?.RowData?.Id ?? null, args?.Left ?? 0, args?.Top ?? 0, cellValue?.ToString());

        await HandleContextMenuOpen.InvokeAsync(menuArgs);
    }

    public async Task OpenWebContextMenu(MouseEventArgs e, Guid? id)
    {
        WebContextMenuArgs menuArgs = new(id, e.ClientX, e.ClientY);

        await HandleContextMenuOpen.InvokeAsync(menuArgs);
    }



5 Replies

PS Prathap Senthil Syncfusion Team May 18, 2026 01:38 PM UTC

Hi Zachary Witt,


Based on the reported issue with the SfGrid component in your Blazor WebAssembly (WASM) application, if you are experiencing an initial delay, we would like to inform you that Interactive WebAssembly or Blazor WebAssembly runs entirely on the client. Before the application can start, the browser must download the .NET runtime (dotnet.wasm), all required assemblies, and application resources. This significantly increases the initial payload and rendering time.


Furthermore, runtime initialization and client-side execution introduce additional overhead, making the startup process slower compared to server-side rendering. This is the primary reason why Interactive WebAssembly has a noticeable delay during the initial load. We have also attached the official Microsoft documentation for your reference.

Additional Reference:

Blazor WebAssembly runtime performance

However, once the page is loaded, you will notice that the Grid loads within 1 second when navigating between pages. For your reference, we have attached a video demonstration.


Video demo : https://drive.google.com/file/d/1Os2Esvl8mC_p4XF1j_NAp54-5CFZr5GF/view

Sample : Please refer to the attachment.

Additionally, to improve performance in the WASM application, please note that the DataGrid renders each row and cell as a component. Rendering a large number of elements can significantly impact memory and CPU usage. To optimize performance, it is recommended to load only the data that is currently visible by using Paging or Virtualization. Also, keep the page size reasonable to avoid reintroducing performance bottlenecks, even when these features are enabled.


Documentation:

https://blazor.syncfusion.com/documentation/datagrid/webassembly-performance

Optimizing Blazor DataGrid Performance | Syncfusion


To enhance performance, we recommend using individual NuGet packages, specifically Syncfusion.Blazor.Grid and Syncfusion.Blazor.Themes, along with their corresponding scripts and themes as shown in the code snippet below.

<head>

    -----------------

    <ImportMap />

    <link rel="icon" type="image/png" rel='nofollow' href="favicon.png" />

    <HeadOutlet />

    <link rel='nofollow' href="_content/Syncfusion.Blazor.Themes/bootstrap5-lite.css" rel="stylesheet" />

 

</head>

 

<body>

    <Routes />

    <script src="@Assets["_framework/blazor.web.js"]"></script>

    <script src="_content/Syncfusion.Blazor.Grid/scripts/sf-grid.min.js" type="text/javascript"></script>

</body>

 

</html>

 

Reference:
Reference script files for Syncfusion Blazor
Blazor themes | Bootstrap, Fluent, Tailwind, Material | Syncfusion


If any issue persists? If so, to further investigate, we need additional clarification from your side. Please provide the following details to help us proceed:


  • To help us analyze the issue, could you provide a simple, reproducible sample with duplicate data that demonstrates the problem? This will allow us to identify the issue more effectively and provide a resolution.

  • Could you please share with us your attempt to replicate the issue using the attached sample?

  • Could you please share the video demonstration of the issue?

The information you provide will be very helpful in validating the reported query on our end and in providing a solution as quickly as possible. Thank you for your understanding.

Regards,
Prathap Senthil


Attachment: BlazorApp6_27cfa8f0.zip


ZW Zachary Witt May 18, 2026 05:11 PM UTC

I modified your sample to show my problems.


I am trying to use the grid in a base component so that it is reusable in a Home Page Template Component..  The main issue in my sample here is that the context menu is taking a long time to open still.  Let me know if I can make improvements to this


Attachment: SyncfusionSlowContextMenuSample_fb2330c3.zip


PS Prathap Senthil Syncfusion Team May 19, 2026 10:05 AM UTC

Thanks for the update.

We have unzipped the attached sample project. However, while the solution file is present, the remaining folders appear to be missing. As a result, we are unable to review the issue you encountered.


Please share the runnable project after removing the bin and obj folders. Additionally, kindly provide a video demonstrating the issue you are facing. Thank you for your understanding.



ZW Zachary Witt May 19, 2026 02:16 PM UTC

Sorry here is the correct zip file.


Attachment: BlazorApp6_aee2377d.7z


PS Prathap Senthil Syncfusion Team May 20, 2026 12:25 PM UTC

Thank you for sharing your scenario and code sample.

Based on the provided implementation, it appears that you are using a standalone ContextMenu component and triggering it manually during the Grid context menu open event by cancelling the default behavior. This approach may be contributing to the delay you are experiencing when opening the context menu. We would like to clarify that the Grid already provides built-in support for add custom context menu items functionality, which is optimized for better performance. Instead of cancelling the Grid’s context menu event and invoking a separate component, we recommend using the built-in ContextMenuItems property along with the ContextMenuItemClicked event. This allows you to define and handle menu actions directly within the Grid, ensuring faster and more efficient rendering. Additionally, you can pass parameters (such as the parent component context) through the event arguments and access them within child components as needed. Kindly refer to the below modified code snippet and sample for your reference.


Documentation: Context Menu in Blazor DataGrid | Syncfusion

Code Snippet:
HomeView.razor

   <SfGrid ID=@($"CompactGrid_{_id}") @ref=@GridRef DataSource=@PaginationDto TValue="BaseDto"

           ContextMenuItems=@_contextMenuItems Toolbar=@_toolbar

           ShowColumnChooser=@true ShouldRenderHiddenColumns=@false EnablePersistence=@true

           RowHeight=@(20) Width="100%" Height="100%" AllowResizing=@true AllowSelection=@false

           AllowPaging="true">

 

       <GridPageSettings PageSize="50"></GridPageSettings>

       <GridEvents TValue="BaseDto" ContextMenuOpen=@OpenSfContextMenu ContextMenuItemClicked="GridContextMenuItemClicked" OnRecordDoubleClick=@SfDoubleClick OnRecordClick=@SfSingleClick />

------
@code {

 

    [Parameter] public required EventCallback<BaseDto> OnRowSingleClick { get; set; }

[Parameter]

public List<ContextMenuItemModel> GridContextMenuitems { get; set; } = new();

 

    [Parameter]

    public EventCallback<ContextMenuClickEventArgs<BaseDto>> GridContextMenuItemClicked { get; set; }

}

Home.razor

@* <SfContextMenu @ref=@ContextMenuRef Items=@MenuItems>

    <MenuEvents TValue=@MenuItemModel ItemSelected=@ContextMenuItemSelected OnOpen=@OnOpen />

</SfContextMenu> *@

 

<SfButton OnClick=@SimulateApiCall Content="Simulate API Call" />

<SfButton OnClick=@ToggleTable Content="ToggleTable" />

 

<HomeView PaginationDto=@PaginationDto GridContextMenuitems="_contextMenuItems" HandleContextMenuOpen=@ContextMenuOpen GridContextMenuItemClicked=@ContextMenuItemSelected Loading=@Loading IsTable=@IsTable>

 

    <WebCompactGridColumns>

        <GridColumn Field="@nameof(BaseDto.Name)" HeaderText="Name" Visible="true" />

        <GridColumn Field="@nameof(BaseDto.EquipmentType)" Visible="true" />

        <GridColumn Field="@nameof(BaseDto.TotalDays)" Visible="true" />

        <GridColumn Field="@nameof(BaseDto.IsDeleted)" Visible="true" DisplayAsCheckBox=@true />

        <GridColumn Field="@nameof(BaseDto.IsTicket)" Visible="true" DisplayAsCheckBox=@true />

    </WebCompactGridColumns>

 

    <WebDetailTemplate>

        <div>This is the detail Template</div>

    </WebDetailTemplate>

 

</HomeView>

 

@code {

 

 

 

    public SfContextMenu<MenuItemModel> ContextMenuRef { get; set; } = new();

    public List<MenuItemModel> MenuItems = new();

    public List<BaseDto> PaginationDto { get; set; } = new();

    public BaseDto? SelectedDto { get; set; } = null;

    public bool Loading { get; set; } = true;

    public bool IsTable { get; set; } = true;

 

    private List<ContextMenuItemModel> _contextMenuItems = new()

{

    new ContextMenuItemModel { Text = "Modify...", Id = "modify", Target = ".e-content" },

    new ContextMenuItemModel { Text = "Overview...", Id = "overview", Target = ".e-content" },

    new ContextMenuItemModel { Text = "Audit...", Id = "audit", Target = ".e-content" },

    new ContextMenuItemModel { Text = "Open Sidebar...", Id = "sidebar", Target = ".e-content" },

 

    new ContextMenuItemModel { Separator = true },

 

  

    new ContextMenuItemModel

    {

        Text = "More Actions",

        Id = "more",

        Target = ".e-content",

        Items = new List<Syncfusion.Blazor.Navigations.MenuItem>

        {

            new Syncfusion.Blazor.Navigations.MenuItem

            {

                Text = "Copy Cell Value",

                Id = "copy",

                IconCss = "bi bi-clipboard"

            },

            new Syncfusion.Blazor.Navigations.MenuItem

            {

                Text = "Share",

                Id = "share",

                IconCss = "bi bi-share"

            },

            new Syncfusion.Blazor.Navigations.MenuItem

            {

                Text = "Duplicate",

                Id = "duplicate",

                IconCss = "bi bi-copy"

            },

 

            new Syncfusion.Blazor.Navigations.MenuItem { Separator = true },

 

            new Syncfusion.Blazor.Navigations.MenuItem

            {

                Text = "Delete",

                Id = "delete",

                IconCss = "bi bi-trash"

            }

        }

    },

 

};

 

----

------

    public async Task ContextMenuItemSelected ( ContextMenuClickEventArgs<BaseDto> args)

    {

        args.PreventRender = true;

        try

        {

            var item = args.Item.Id;

            Console.WriteLine(item);

        }

        catch (Exception) { }

    }

---- 

}

 


Sample: Check the attachment .

Furthermore, to improve Grid performance in a Blazor WebAssembly application, we suggest keeping the page size at a reasonable level (for example, around 15 or based on your requirements), even when using paging or virtualization, as very large page sizes can still introduce performance bottlenecks. You may refer to this documentation for more details:


https://blazor.syncfusion.com/documentation/datagrid/webassembly-performance#use-paging-or-virtualization-to-load-only-visible-rows

Another important optimization is to avoid unnecessary component re-renders after Grid events. When handling Grid events, you can set the PreventRender property on the event arguments (where applicable) to true, which prevents the Grid from re-rendering unnecessarily and improves responsiveness. For more information, please refer to:


Documentation: https://blazor.syncfusion.com/documentation/datagrid/webassembly-performance#avoid-unnecessary-component-renders-after-blazor-datagrid-events


Code Snippet:

public void SfSingleClick(RecordClickEventArgs<BaseDto> args)

{

     args.PreventRender = true;

        

     Console.WriteLine($"Single click: {args.RowData.Id}");

}

 

public void SfDoubleClick(RecordDoubleClickEventArgs<BaseDto> args)

{

     args.PreventRender = true;

        

     Console.WriteLine($"Double click: {args.RowData.Id}");

}

 

Home.razor
    public async Task ContextMenuItemSelected ( ContextMenuClickEventArgs<BaseDto> args)

    {

        args.PreventRender = true;

        try

        {

            var item = args.Item.Id;

            Console.WriteLine(item);

        }

        catch (Exception) { }

    }

 

 


Please get back to us if you need further assistance.


Attachment: BlazorApp6_588da5ac.zip

Loader.
Up arrow icon