DataGrid - Experimental

A sortable, filterable data grid with multiselection and pagination.

Default Data Grid

The <MudDataGrid> is used to display and work with small amounts of data up to very large datasets, easily and efficiently. In it's simplest form, the data grid is a just a table, displaying data from a data source.

Nr
Sign
Name
Position
Molar mass
1 H Hydrogen 0 1.00794
2 He Helium 17 4.002602
3 Li Lithium 0 6.941
4 Be Beryllium 1 9.012182
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid Items="@Elements.Take(4)">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
    </Columns>
</MudDataGrid>
@code { 
    private IEnumerable<Element> Elements = new List<Element>();

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }
}
Advanced Data Grid

In a more advanced scenario, the data grid offers sorting, filtering, pagination and selection. There are two ways to filter the data fed into the data grid. A QuickFilter function allows filtering the items in the grid globally. Data can also be filtered by specifying column filters, enabling a more robust filtration.

In this example, we turn sorting and filtering off for the Nr column using the boolean Sortable and Filterable properties as well as hide the column options icon button by setting the ShowColumnOptions property to false (which is hidden by default). Additionally, we can override the default SortBy function for each column, seen in the Name column where we show how you can switch to a sort by the Name's length.

To hide the filter icons unless a column is currently filtered, you can set the ShowFilterIcons property to false.

Periodic Elements
NrSign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)
6 C Carbon 13 12.0107 Nonmetal Carbon (p)
7 N Nitrogen 14 14.0067 Nonmetal Pnictogen (p)
8 O Oxygen 15 15.9994 Nonmetal Chalcogen (p)
9 F Fluorine 16 18.998404 Halogen (p)
10 Ne Neon 17 20.1797 Noble Gas (p)

Rows per page:

10

1-10 of 88

Show Events
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" MultiSelection="true" Items="@Elements" SortMode="SortMode.Multiple" Filterable="true" QuickFilter="@_quickFilter"
    Hideable="true" RowClick="@RowClicked" SelectedItemsChanged="@SelectedItemsChanged">
    <ToolBarContent>
        <MudText Typo="Typo.h6">Periodic Elements</MudText>
        <MudSpacer />
        <MudTextField @bind-Value="_searchString" Placeholder="Search" Adornment="Adornment.Start" Immediate="true"
            AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
    </ToolBarContent>
    <Columns>
        <SelectColumn T="Element" />
        <Column T="Element" Field="Number" Title="Nr" Sortable="false" Filterable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" SortBy="@_sortBy" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="@_sortNameByLength" Color="Color.Primary">Sort Name Column By Length</MudSwitch>
</div>

<MudExpansionPanels Style="flex:1">
    <MudExpansionPanel Text="Show Events">
        @foreach (var message in _events)
        {
            <MudText Typo="@Typo.body2">@message</MudText>
        }
        @if(_events.Count > 0) 
        {
            <div class="d-flex">
                <MudSpacer/>
                <MudButton Class="mt-3" ButtonType="ButtonType.Button" Variant="Variant.Filled" OnClick="@(() => _events.Clear())">Clear</MudButton>
            </div>
        }
    </MudExpansionPanel>
</MudExpansionPanels>
@code {
    private IEnumerable<Element> Elements = new List<Element>();
    private string _searchString;
    private bool _sortNameByLength;
    private List<string> _events = new();
    // custom sort by name length
    private Func<Element, object> _sortBy => x =>
    {
        if (_sortNameByLength)
            return x.Name.Length;
        else
            return x.Name;
    };
    // quick filter - filter gobally across multiple columns with the same input
    private Func<Element, bool> _quickFilter => x =>
    {
        if (string.IsNullOrWhiteSpace(_searchString))
            return true;

        if (x.Sign.Contains(_searchString, StringComparison.OrdinalIgnoreCase))
            return true;

        if (x.Name.Contains(_searchString, StringComparison.OrdinalIgnoreCase))
            return true;

        if ($"{x.Number} {x.Position} {x.Molar}".Contains(_searchString))
            return true;

        return false;
    };

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }

    // events
    void RowClicked(DataGridRowClickEventArgs<Element> args)
    {
        _events.Insert(0, $"Event = RowClick, Index = {args.RowIndex}, Data = {System.Text.Json.JsonSerializer.Serialize(args.Item)}");
    }

    void SelectedItemsChanged(HashSet<Element> items)
    {
        _events.Insert(0, $"Event = SelectedItemsChanged, Data = {System.Text.Json.JsonSerializer.Serialize(items)}");
    }
}
Visual Styling

The <MudDataGrid> has many built in properties to change its style and also allows for custom styling as well.

Row level classes and styles can be applied using the RowClass and RowStyle properties respectively. To style rows according to the data of the row, you would use the RowClassFunc and RowStyleFunc properties. For even finer grain control, you can style at the header, cell and footer level as well by using the CellClass, CellStyle, CellClassFunc, CellStyleFunc, etc. properties. However, the header and footer do not have the Func properties since they are not needed.

Nr
Sign
Name
Position
Molar mass
1 H Hydrogen 0 1.00794
2 He Helium 17 4.002602
3 Li Lithium 0 6.941
4 Be Beryllium 1 9.012182
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid Items="@Elements.Take(4)" Hover="@_hover" Dense="@_dense" Striped="@_striped" Bordered="@_bordered"
    RowStyleFunc="@_rowStyleFunc">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" CellStyleFunc="@_cellStyleFunc" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
    </Columns>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="@_hover" Color="Color.Primary">Hover</MudSwitch>
    <MudSwitch @bind-Checked="@_dense" Color="Color.Secondary">Dense</MudSwitch>
    <MudSwitch @bind-Checked="@_striped" Color="Color.Tertiary">Striped</MudSwitch>
    <MudSwitch @bind-Checked="@_bordered" Color="Color.Warning">Bordered</MudSwitch>
</div>
@code {
    private IEnumerable<Element> Elements = new List<Element>();
    private bool _hover;
    private bool _dense;
    private bool _striped;
    private bool _bordered;
    // style the rows where the Element.Position == 0 to have italic text.
    private Func<Element, int, string> _rowStyleFunc => (x, i) =>
    {
        if (x.Position == 0)
            return "font-style:italic";

        return "";
    };
    // style the cells according to the element's physical classification and the molar mass.
    private Func<Element, string> _cellStyleFunc => x =>
    {
        string style = "";

        if (x.Number == 1)
            style += "background-color:#8CED8C";

        else if (x.Number == 2)
            style += "background-color:#E5BDE5";

        else if (x.Number == 3)
            style += "background-color:#EACE5D";

        else if (x.Number == 4)
            style += "background-color:#F1F165";

        if (x.Molar > 5)
            style += ";font-weight:bold";

        return style;
    };

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }
}
Editing

The <MudDataGrid> allows editing the data passed into it. Setting the ReadOnly property to false and the EditMode property to turns editing. There are two different edit modes: Cell and Form. Form displays a form in a popup when editing. Cell is more like excel where each cell is ready to edit and as you make edits, they are applied to the data source. To disable editing on a column, set its IsEditable property to false.

By default, the built in editing in the data grid automatically supplies the proper input component for each cell. However, this can be overidden by supplying an <EditTemplate>. Inside the template, you have full control over the editing. Take a look at the Position column below.

Nr
Sign
Name
Position
Molar mass
1 H Hydrogen 0 1.00794
2 He Helium 17 4.002602
3 Li Lithium 0 6.941
4 Be Beryllium 1 9.012182

Form

Manual

Show Events
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements.Take(4)" ReadOnly="@_readOnly" EditMode="@(_isCellEditMode ? DataGridEditMode.Cell : DataGridEditMode.Form)"
    StartedEditingItem="@StartedEditingItem" CancelledEditingItem="@CancelledEditingItem" CommittedItemChanges="@CommittedItemChanges"
    Bordered="true" Dense="true" EditTrigger="@(_editTriggerRowClick ? DataGridEditTrigger.OnRowClick : DataGridEditTrigger.Manual)">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" IsEditable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position">
            <EditTemplate>
                <MudSelect @bind-Value="context.Item.Position" Required RequiredError="You must select a Position!!!" Margin="@Margin.Dense">
                    <MudSelectItem Value="0">zero</MudSelectItem>
                    <MudSelectItem Value="1">one</MudSelectItem>
                    <MudSelectItem Value="17">seventeen</MudSelectItem>
                </MudSelect>
            </EditTemplate>
        </Column>
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Hidden="@(_isCellEditMode || _readOnly || _editTriggerRowClick)" CellClass="d-flex justify-end">
            <CellTemplate>
                <MudIconButton Size="@Size.Small" Icon="@Icons.Outlined.Edit" OnClick="@context.Actions.StartEditingItem" />
            </CellTemplate>
        </Column>
    </Columns>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="@_readOnly" Color="Color.Primary">Read Only</MudSwitch>
    <div class="d-flex justify-start align-center">
        <p class="mud-typography mud-typography-body1 mud-inherit-text mr-2">Form</p>
        <MudSwitch @bind-Checked="@_isCellEditMode">Cell</MudSwitch>
    </div>
    <div class="d-flex justify-start align-center">
        <p class="mud-typography mud-typography-body1 mud-inherit-text mr-2">Manual</p>
        <MudSwitch @bind-Checked="@_editTriggerRowClick">On Row Click</MudSwitch>
    </div>
</div>

<MudExpansionPanels Style="flex:1">
    <MudExpansionPanel Text="Show Events">
        @foreach (var message in _events)
        {
            <MudText Typo="@Typo.body2">@message</MudText>
        }
        @if(_events.Count > 0) 
        {
            <div class="d-flex">
                <MudSpacer/>
                <MudButton Class="mt-3" ButtonType="ButtonType.Button" Variant="Variant.Filled" OnClick="@(() => _events.Clear())">Clear</MudButton>
            </div>
        }
    </MudExpansionPanel>
</MudExpansionPanels>
@code {
    private IEnumerable<Element> Elements = new List<Element>();
    private bool _readOnly;
    private bool _isCellEditMode;
    private List<string> _events = new();
    private bool _editTriggerRowClick;

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }

    // events
    void StartedEditingItem(Element item)
    {
        _events.Insert(0, $"Event = StartedEditingItem, Data = {System.Text.Json.JsonSerializer.Serialize(item)}");
    }

    void CancelledEditingItem(Element item)
    {
        _events.Insert(0, $"Event = CancelledEditingItem, Data = {System.Text.Json.JsonSerializer.Serialize(item)}");
    }

    void CommittedItemChanges(Element item)
    {
        _events.Insert(0, $"Event = CommittedItemChanges, Data = {System.Text.Json.JsonSerializer.Serialize(item)}");
    }
}
Grouping

The <MudDataGrid> allows you to group data by column. Setting the Grouping property to true will turn on grouping which will add a menu item in the column options to toggle grouping of that column. To disable grouping on a column, set its Groupable property to false.

Periodic Elements
Nr
Sign
Name
Position
Molar mass
Category
Category: Other
Category: Noble Gas (p)
Category: Alkaline Earth Metal (s)
Category: Alkaline Metal (s)
Category: Metalloid Boron (p)
Category: Nonmetal Carbon (p)
Category: Nonmetal Pnictogen (p)
Category: Nonmetal Chalcogen (p)
Category: Halogen (p)

Rows per page:

10

1-10 of 88

@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid @ref="dataGrid" MultiSelection="true" Items="@Elements" Sortable="true" Filterable="true"
    Hideable="true" Groupable="true" GroupExpanded="false">
    <ToolBarContent>
        <MudText Typo="Typo.h6">Periodic Elements</MudText>
        <MudSpacer />
    </ToolBarContent>
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" Filterable="false" Groupable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" Grouping="true" GroupBy="@_groupBy">
            <GroupTemplate>
                @if (_customizeGroupTemplate)
                {
                    <span style="font-weight:bold">Group: @context.Grouping.Key <MudChip Variant="Variant.Outlined" Color="Color.Primary" Size="Size.Small">total @context.Grouping.Count()</MudChip></span>
                }
                else
                {
                    <span style="font-weight:bold">Category: @context.Grouping.Key</span>
                }
            </GroupTemplate>
        </Column>
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="_customizeGroupTemplate" Color="@Color.Primary">Customize Group Template</MudSwitch>
    <MudSwitch T="bool" Checked="@_customizeGroupBy" Color="@Color.Primary" CheckedChanged="@CustomizeByGroupChanged">Customize Group By</MudSwitch>
    <MudButton OnClick="@ExpandAllGroups" Color="@Color.Primary">Expand All</MudButton>
    <MudButton OnClick="@CollapseAllGroups" Color="@Color.Primary">Collapse All</MudButton>
</div>
@code {
    IEnumerable<Element> Elements = new List<Element>();
    MudDataGrid<Element> dataGrid;
    bool _customizeGroupTemplate;
    static bool _customizeGroupBy;
    static string[] _nonmetals = new string[] { "H", "He","N", "O", "F", "Ne", "Cl", "Ar", "Kr", "Xe", "Rn", "Br", "C", "P", "Se", "Se", "I" };
    Func<Element, object> _groupBy = x => 
    {
        if (_customizeGroupBy)
        {
            if (_nonmetals.Contains(x.Sign))
                return "Nonmetal";

            return "Metal";
        }

        return x.Group;
    };

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }

    void ExpandAllGroups()
    {
        dataGrid?.ExpandAllGroups();
    }

    void CollapseAllGroups()
    {
        dataGrid?.CollapseAllGroups();
    }

    void CustomizeByGroupChanged(bool isChecked)
    {
        _customizeGroupBy = isChecked;
        dataGrid.GroupItems();
    }
}
Sorting

The <MudDataGrid> allows you to either disable sorting entirely, sort by single column or by multiple columns via the SortMode property. The default (SortMode.Multiple) allows sorting on more than one column (Hold Ctrl-Key) while clicking on a header column to extend the sort operation to another column.
Clicking on the column header while Alt-Key is pressed, will un-sort a column (or remove it from the set of sorted columns) when multiple sorting is enabled. In the case of multiple sorting, a small index-number next to the sort direction arrow will indicate the order in which columns are sorted.
When mode is set to SortMode.Single, only a single column can be used for sorting at a time. Using another column for sorting will automatically un-sort any former sorted column. In single mode, the number indicator next to the direction arrow will not be shown.

In both active modes, single columns can be excluded from sorting by setting the Sortable property to false for that column. When SortMode is set to SortMode.None sorting is disabled globally and setting the Sortable property on a column has no effect.

NrSign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)
6 C Carbon 13 12.0107 Nonmetal Carbon (p)
7 N Nitrogen 14 14.0067 Nonmetal Pnictogen (p)
8 O Oxygen 15 15.9994 Nonmetal Chalcogen (p)
9 F Fluorine 16 18.998404 Halogen (p)
10 Ne Neon 17 20.1797 Noble Gas (p)

Rows per page:

10

1-10 of 88

@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements" SortMode="@_sortMode">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" Sortable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" SortBy="@_sortBy" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="@_sortNameByLength" Color="Color.Primary">Sort Name Column By Length</MudSwitch>
    <MudRadioGroup T=SortMode @bind-SelectedOption="@_sortMode">
        <MudRadio Dense=true Option=@SortMode.Multiple Color="Color.Primary">Multiple</MudRadio>
        <MudRadio Dense=true Option=@SortMode.Single Color="Color.Tertiary">Single</MudRadio>
        <MudRadio Dense=true Option=@SortMode.None >None</MudRadio>
    </MudRadioGroup>
</div>
@code {
    private IEnumerable<Element> Elements = new List<Element>();
    private bool _sortNameByLength;
    private SortMode _sortMode = SortMode.Multiple;

    // custom sort by name length
    private Func<Element, object> _sortBy => x =>
    {
        if (_sortNameByLength)
            return x.Name.Length;
        else
            return x.Name;
    };

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }
}
Filtering

The <MudDataGrid> supports filtering with several different DataGridFilterModes by setting the FilterMode property. DataGridFilterMode.Simple is the default where all filters are managed in one popover in the data grid. It allows you to set multiple filters at one time for multiple different columns. In DataGridFilterMode.ColumnFilterMenu mode, there is a dedicated popover for each column. Lastly, DataGridFilterMode.ColumnFilterRow allows you to inline the filtering behavior directly into the data grid.

Nr
Sign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)
6 C Carbon 13 12.0107 Nonmetal Carbon (p)
7 N Nitrogen 14 14.0067 Nonmetal Pnictogen (p)
8 O Oxygen 15 15.9994 Nonmetal Chalcogen (p)
9 F Fluorine 16 18.998404 Halogen (p)
10 Ne Neon 17 20.1797 Noble Gas (p)

Rows per page:

10

1-10 of 88

@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements" Filterable="true" FilterMode="@_filterMode">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" Filterable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudRadioGroup T="DataGridFilterMode" @bind-SelectedOption="@_filterMode">
        <MudRadio Dense="true" Option="@DataGridFilterMode.Simple" Color="Color.Primary">Simple</MudRadio>
        <MudRadio Dense="true" Option="@DataGridFilterMode.ColumnFilterMenu" Color="Color.Tertiary">Column Menu</MudRadio>
        <MudRadio Dense="true" Option="@DataGridFilterMode.ColumnFilterRow">Column Row</MudRadio>
    </MudRadioGroup>
</div>
@code {
    IEnumerable<Element> Elements = new List<Element>();
    DataGridFilterMode _filterMode = DataGridFilterMode.Simple;

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }
}
Advanced Filtering

It is possible to customize filtering by utilizing the <FilterTemplate> available on the <MudDataGrid> as well as each <Column>. In the example below, the Sign column is customized.

Inside of the <FilterTemplate> on the data grid while using DataGridFilterMode.Simple, the context is set to the data grid's FilterDefinitions to allow for customizing the filtering behavior.

When using the <FilterTemplate> in the column specific filter modes, the context is a DataGridFilterMode.Simple which gives access to several helpful properties and actions. For example, the current FilterDefinition related to the column is available as well as several actions to make it easier to implement custom filter behavior such as ApplyFilter and ClearFilter.

Nr
Sign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)
6 C Carbon 13 12.0107 Nonmetal Carbon (p)
7 N Nitrogen 14 14.0067 Nonmetal Pnictogen (p)
8 O Oxygen 15 15.9994 Nonmetal Chalcogen (p)
9 F Fluorine 16 18.998404 Halogen (p)
10 Ne Neon 17 20.1797 Noble Gas (p)

Rows per page:

10

1-10 of 88

@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements" Filterable="true" FilterMode="@DataGridFilterMode.ColumnFilterRow">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" Filterable="false" />
        <Column T="Element" Field="Sign">
            <FilterTemplate>
                <MudIconButton OnClick="@OpenFilter" Icon="@_icon" Size="@Size.Small" />
                <MudOverlay Visible="@_filterOpen" OnClick="@(() => _filterOpen = false)" />
                <MudPopover Open="@_filterOpen" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter"
                    Style="width:150px">
		           <MudStack Spacing="0">
                       <MudCheckBox T="bool" Label="Select All" Size="@Size.Small" Checked="@_selectAll" CheckedChanged="@SelectAll" />
                       <MudStack Spacing="0" Style="overflow-y:auto;max-height:250px">
                           @foreach (var item in context.Items)
                           {
                               <MudCheckBox T="bool" Label="@($"{item.Sign}")" Size="@Size.Small" Checked="@(_selectedItems.Contains(item))"
                                   CheckedChanged="@((value) => SelectedChanged(value, item))" />
                           }
                       </MudStack>
                       <MudStack Row="true">
                            <MudButton OnClick="@(() => ClearFilter(context))">Clear</MudButton>
                            <MudButton Color="@Color.Primary" OnClick="@(() => ApplyFilter(context))">Filter</MudButton>
                       </MudStack>
                   </MudStack>
	            </MudPopover>
            </FilterTemplate>
        </Column>
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" />
    </PagerContent>
</MudDataGrid>
@code {
    IEnumerable<Element> Elements = new List<Element>();
    HashSet<Element> _selectedItems = new();
    HashSet<Element> _filterItems = new();
    FilterDefinition<Element> _filterDefinition;
    bool _selectAll = true;
    string _icon = Icons.Outlined.FilterAlt;

    bool _filterOpen = false;

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
        _selectedItems = Elements.ToHashSet();
        _filterItems = Elements.ToHashSet();
        _filterDefinition = new FilterDefinition<Element>
        {
            FilterFunction = x => _filterItems.Contains(x)
        };
    }

    void OpenFilter()
    {
        _filterOpen = true;
    }

    void SelectedChanged(bool value, Element item)
    {
        if (value)
            _selectedItems.Add(item);
        else
            _selectedItems.Remove(item);

        if (_selectedItems.Count == Elements.Count())
            _selectAll = true;
        else
            _selectAll = false;
    }

    void ClearFilter(FilterContext<Element> context)
    {
        _selectedItems = Elements.ToHashSet();
        _filterItems = Elements.ToHashSet();
        _icon = Icons.Outlined.FilterAlt;
        context.Actions.ClearFilter(_filterDefinition);
        _filterOpen = false;
    }

    void ApplyFilter(FilterContext<Element> context)
    {
        _filterItems = _selectedItems.ToHashSet();
        _icon = _filterItems.Count == Elements.Count() ? Icons.Outlined.FilterAlt : Icons.Filled.FilterAlt;
        context.Actions.ApplyFilter(_filterDefinition);
        _filterOpen = false;
    }

    void SelectAll(bool value)
    {
        _selectAll = value;

        if (value)
        {
            _selectedItems = Elements.ToHashSet();
        }
        else
        {
            _selectedItems.Clear();
        }
    }
}
Resizing

The <MudDataGrid> allows you to resize columns interactively when ColumnResizeMode is not set to None, which is the default. There are two modes for resizing: ResizeMode.Container and ResizeMode.Column. ResizeMode.Container resizes the entire data grid while ResizeMode.Column only resizes columns using available space within the data grid.

Nr
Sign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)

Rows per page:

5

1-5 of 88

ResizeMode.Container

@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="Element" Items="@Elements" ColumnResizeMode="@(_resizeColumn ? ResizeMode.Column : ResizeMode.Container)" RowsPerPage="5">
    <Columns>
        <Column T="Element" Field="Number" Title="Nr" Resizable="false" />
        <Column T="Element" Field="Sign" />
        <Column T="Element" Field="Name" />
        <Column T="Element" Field="Position" />
        <Column T="Element" Field="Molar" Title="Molar mass" />
        <Column T="Element" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="Element" PageSizeOptions=@(new int[] {5, 10, 20}) />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <div class="d-flex justify-start align-center">
        <p class="mud-typography mud-typography-body1 mud-inherit-text mr-2">ResizeMode.Container</p>
        <MudSwitch @bind-Checked="@_resizeColumn">ResizeMode.Column</MudSwitch>
    </div>
</div>
@code {
    private IEnumerable<Element> Elements = new List<Element>();
    private bool _resizeColumn;

    protected override async Task OnInitializedAsync()
    {
        Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
    }
}
Data Aggregation

The <MudDataGrid> allows you to aggregate data in several different ways. Data aggregation happens in the footer of the grid for the most part. By setting an AggregateDefinition, you can easily add a quick built-in aggregate or choose to tailor the display to your needs. There are 6 different AggregateTypes that can be used with the AggregateDefinition: Avg, Count, Custom, Max, Min and Sum. For more control over the data aggregation, you can choose the AggregationType.Custom and supply your own function which will return a formatted string to display. Lastly, for complete control over the data aggregation including the look and feel, you use <FooterTemplate> which has it's context set to the CurrentPageItems.

Aggregation is automatically applied to groups when the data grid is grouped by a column. Try it out by grouping the Status column!

Name
Age
Status
Salary
Hired
Manager
Sam 56 Normal 50000.00 3/5/2005 False
Alicia 54 Info 75000.00 1/17/2010 False
Ira 27 Success 102000.00 6/15/2017 True
John 32 Warning 132000.00 12/23/2021 True
Fred 65 Warning 87000.00 7/3/2003 False
Tabitha 33 Info 157000.00 2/12/2015 True
Hunter 22 Success 43000.00 9/20/2017 False
Esme 55 Warning 149000.00 8/1/2017 True
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid Items="@_items" Groupable="true" Filterable="true">
    <Columns>
        <Column T="Model" Field="@nameof(Model.Name)">
            <FooterTemplate>
                @{ int index = 1, count = @context.Items.Count(); }
                People: 
                @foreach (var person in @context.Items)
                {
                    <MudAvatar Color="@((Color)index)" Variant="Variant.Outlined" Size="Size.Small" Class="mr-1">@person.Name.First()</MudAvatar>@person.Name.Substring(1)
                    if (index < count)
                    {
                        @(", ")
                    }
                    index++;
                }
            </FooterTemplate>
        </Column>
        <Column T="Model" Field="@nameof(Model.Age)" AggregateDefinition="_ageAggregation" />
        <Column T="Model" Field="@nameof(Model.Status)" ></Column>
        <Column T="Model" Field="@nameof(Model.Salary)" AggregateDefinition="_salaryAggregation" />
        <Column T="Model" Field="HireDate" Title="Hired">
            <CellTemplate>
                @context.Item.HireDate.ToString("d")
            </CellTemplate>
        </Column>
        <Column T="Model" Field="IsManager" Title="Manager" />
    </Columns>
</MudDataGrid>
@code { 
    public record Model (string Name, int Age, Severity Status, decimal Salary, DateTime HireDate, bool IsManager);

    IEnumerable<Model> _items = new List<Model>()
    {
        new Model("Sam", 56, Severity.Normal, 50_000.00M, new DateTime(2005, 3, 5), false), 
        new Model("Alicia", 54, Severity.Info, 75_000.00M, new DateTime(2010, 1, 17), false), 
        new Model("Ira", 27, Severity.Success, 102_000.00M, new DateTime(2017, 6, 15), true),
        new Model("John", 32, Severity.Warning, 132_000.00M, new DateTime(2021, 12, 23), true),
        new Model("Fred", 65, Severity.Warning, 87_000.00M, new DateTime(2003, 7, 3), false), 
        new Model("Tabitha", 33, Severity.Info, 157_000.00M, new DateTime(2015, 2, 12), true), 
        new Model("Hunter", 22, Severity.Success, 43_000.00M, new DateTime(2017, 9, 20), false),
        new Model("Esme", 55, Severity.Warning, 149_000.00M, new DateTime(2017, 8, 1), true)
    };

    AggregateDefinition<Model> _ageAggregation = new AggregateDefinition<Model>
    {
        Type = AggregateType.Avg,
        DisplayFormat = "Average age is {value}"
    };

    AggregateDefinition<Model> _salaryAggregation = new AggregateDefinition<Model>
    {
        Type = AggregateType.Custom,
        CustomAggregate = x =>
        {
            var highestSalary = x.Max(z => z.Salary);
            var countOver100Grand = x.Count(z => z.Salary > 100_000);
            return $"Highest: {highestSalary.ToString("C0")} | {countOver100Grand} Over {100000:C0}";
        }
    };
}
Advanced Data Grid Using IDictionary

This example uses a List<IDictionary<string, object>> for the Items data source.

In a more advanced scenario, the data grid offers sorting, filtering, pagination and selection. There are two ways to filter the data fed into the data grid. A QuickFilter function allows filtering the items in the grid globally. Data can also be filtered by specifying column filters, enabling a more robust filtration.

In this example, we turn sorting and filtering off for the Nr column using the boolean Sortable and Filterable properties as well as hide the column options icon button by setting the ShowColumnOptions property to false. Additionally, we can override the default SortBy function for each column, seen in the Name column where we show how you can switch to a sort by the Name's length.

Periodic Elements
NrSign
Name
Position
Molar mass
Category
1 H Hydrogen 0 1.00794 Other
2 He Helium 17 4.002602 Noble Gas (p)
3 Li Lithium 0 6.941 Alkaline Earth Metal (s)
4 Be Beryllium 1 9.012182 Alkaline Metal (s)
5 B Boron 12 10.811 Metalloid Boron (p)
6 C Carbon 13 12.0107 Nonmetal Carbon (p)
7 N Nitrogen 14 14.0067 Nonmetal Pnictogen (p)
8 O Oxygen 15 15.9994 Nonmetal Chalcogen (p)
9 F Fluorine 16 18.998404 Halogen (p)
10 Ne Neon 17 20.1797 Noble Gas (p)

Rows per page:

10

1-10 of 88

Show Events
@using System.Text.Json
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@inject HttpClient httpClient

<MudDataGrid T="IDictionary<string, object>" MultiSelection="true" Items="@Elements" Sortable="true" Filterable="true" QuickFilter="@_quickFilter"
    Hideable="true" RowClick="@RowClicked" SelectedItemsChanged="@SelectedItemsChanged">
    <ToolBarContent>
        <MudText Typo="Typo.h6">Periodic Elements</MudText>
        <MudSpacer />
        <MudTextField @bind-Value="_searchString" Placeholder="Search" Adornment="Adornment.Start" Immediate="true"
            AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
    </ToolBarContent>
    <Columns>
        <SelectColumn T="IDictionary<string, object>" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(int)" Field="Number" Title="Nr" Sortable="false" Filterable="false" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(string)" Field="small" Title="Sign" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(string)" Field="Name" SortBy="@_sortBy" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(int)" Field="Position" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(decimal)" Field="Molar" Title="Molar mass" />
        <Column T="IDictionary<string, object>" FieldType="@typeof(string)" Field="Group" Title="Category" />
    </Columns>
    <PagerContent>
        <MudDataGridPager T="IDictionary<string, object>" />
    </PagerContent>
</MudDataGrid>

<div class="d-flex flex-wrap mt-4">
    <MudSwitch @bind-Checked="@_sortNameByLength" Color="Color.Primary">Sort Name Column By Length</MudSwitch>
</div>

<MudExpansionPanels Style="flex:1">
    <MudExpansionPanel Text="Show Events">
        @foreach (var message in _events)
        {
            <MudText Typo="@Typo.body2">@message</MudText>
        }
        @if(_events.Count > 0) 
        {
            <div class="d-flex">
                <MudSpacer/>
                <MudButton Class="mt-3" ButtonType="ButtonType.Button" Variant="Variant.Filled" OnClick="@(() => _events.Clear())">Clear</MudButton>
            </div>
        }
    </MudExpansionPanel>
</MudExpansionPanels>
@code {
    private IEnumerable<IDictionary<string, object>> Elements = new List<IDictionary<string, object>>();
    private string _searchString;
    private bool _sortNameByLength;
    private List<string> _events = new();
    // custom sort by name length
    private Func<IDictionary<string, object>, object> _sortBy => x =>
    {
        if (_sortNameByLength)
            return x["Name"].ToString().Length;
        else
            return x["Name"].ToString();
    };
    // quick filter - filter gobally across multiple columns with the same input
    private Func<IDictionary<string, object>, bool> _quickFilter => x =>
    {
        if (string.IsNullOrWhiteSpace(_searchString))
            return true;

        if (x["small"].ToString().Contains(_searchString, StringComparison.OrdinalIgnoreCase))
            return true;

        if (x["Name"].ToString().Contains(_searchString, StringComparison.OrdinalIgnoreCase))
            return true;

        if ($"{x["Number"]} {x["Position"]} {x["Molar"]}".Contains(_searchString))
            return true;

        return false;
    };

    protected override async Task OnInitializedAsync()
    {
        var elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
        var serialized = JsonSerializer.Serialize(elements);
        Elements = JsonSerializer.Deserialize<List<IDictionary<string, object>>>(serialized);
    }

    // events
    void RowClicked(DataGridRowClickEventArgs<IDictionary<string, object>> args)
    {
        _events.Insert(0, $"Event = RowClick, Index = {args.RowIndex}, Data = {System.Text.Json.JsonSerializer.Serialize(args.Item)}");
    }

    void SelectedItemsChanged(HashSet<IDictionary<string, object>> items)
    {
        _events.Insert(0, $"Event = SelectedItemsChanged, Data = {System.Text.Json.JsonSerializer.Serialize(items)}");
    }
}
Sticky Columns

The <MudDataGrid> allows you to make a column stick to the left or right. Setting the StickyLeft or StickyRight properties to true will make those columns "sticky". You must turn on HorizontalScrollbar to see the columns stick to either side.

There are a couple of things to keep in mind with sticky columns. First, if there are not enough columns and data to force the data grid to scroll, you will not see the columns stick, and that is by design and simply how sticky works in CSS. Secondly, there is nothing stopping you from making multiple columns sticky, but it will not have the effect you presumably intend. Instead, each column will be sticky when it reached the left or right side of the data grid and will overlap the sticky column before it.

Name
Age
This is a really long column                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        ...
Salary
Sam 56 ... 50000.00
Alicia 54 ... 75000.00
Ira 27 ... 102000.00
John 32 ... 132000.00
@using System.Net.Http.Json

<MudDataGrid Items="@_users" HorizontalScrollbar="true" Bordered="true" Dense="true">
    <Columns>
        <Column T="User" Field="Name" StickyLeft="true" />
        <Column T="User" Field="Age" />
        <Column T="User" Field="FillerColumn" HeaderStyle="white-space:nowrap">
            <HeaderTemplate>
                @((MarkupString)$"This is a really long column{string.Join("", Enumerable.Repeat("&nbsp;", 1000))}...")
            </HeaderTemplate>
        </Column>
        <Column T="User" Field="Salary" />
        <Column T="User" StickyRight="true">
            <CellTemplate>
                <MudIconButton Icon="@Icons.Material.Outlined.Edit" Size="@Size.Small" />
            </CellTemplate>
        </Column>
    </Columns>
</MudDataGrid>
@code {
    public record User(string Name, int Age, string FillerColumn, decimal Salary);

    private IEnumerable<User> _users = new List<User>
    {
        new User("Sam", 56, "...", 50_000.00M), 
        new User("Alicia", 54, "...", 75_000.00M), 
        new User("Ira", 27, "...", 102_000.00M),
        new User("John", 32, "...", 132_000.00M),

    };
}
Virtualization

The items in the <MudDataGrid> can be virtualized to provider better rendering performance. Setting the Virtualize property to true will cause the items to be rendered virtually. You must restrict the height for virtualization to work.

Column1
Column2
Column3
Column4
Column5
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models

<MudDataGrid Items="@_items" Virtualize="true" FixedHeader="true" Height="350px">
    <Columns>
        <Column T="Model" Field="Column1" />
        <Column T="Model" Field="Column2" />
        <Column T="Model" Field="Column3" />
        <Column T="Model" Field="Column4" />
        <Column T="Model" Field="Column5" />
    </Columns>
</MudDataGrid>
@code {
    public record Model(string Column1, string Column2, string Column3, string Column4, string Column5);

    private List<Model> _items = new List<Model>();

    protected override void OnInitialized()
    {
        for (var i = 0; i < 20000; i++)
            _items.Add(new Model($"Value_{i}", $"Value_{i}", $"Value_{i}", $"Value_{i}", $"Value_{i}"));
    }
}
Observability

When loading the <MudDataGrid> with a collection that implements INotifyCollectionChanged, changes to the underlying collection will automatically be reflected in the <MudDataGrid>.

Name
Age
Status
Salary
Hired
Manager
Sam 56 Normal 50000.00 3/5/2005 12:00:00 AM False
Alicia 54 Info 75000.00 1/17/2010 12:00:00 AM False
Ira 27 Success 102000.00 6/15/2017 12:00:00 AM True
John 32 Warning 132000.00 12/23/2021 12:00:00 AM True
Fred 65 Warning 87000.00 7/3/2003 12:00:00 AM False
Tabitha 33 Info 157000.00 2/12/2015 12:00:00 AM True
Hunter 22 Success 43000.00 9/20/2017 12:00:00 AM False
Esme 55 Warning 149000.00 8/1/2017 12:00:00 AM True
@using System.Net.Http.Json
@using System.Collections.ObjectModel
@inject HttpClient httpClient

<MudButton OnClick="@AddItem" Color="@Color.Success" Class="add-item-btn">Add Item</MudButton>
<MudButton OnClick="@RemoveItem" Color="@Color.Error" Class="remove-item-btn">Remove Item</MudButton>

<MudDataGrid Items="@_items">
    <Columns>
        <Column T="Model" Field="@nameof(Model.Name)" />
        <Column T="Model" Field="@nameof(Model.Age)" />
        <Column T="Model" Field="@nameof(Model.Status)" />
        <Column T="Model" Field="@nameof(Model.Salary)" />
        <Column T="Model" Field="HireDate" Title="Hired" />
        <Column T="Model" Field="IsManager" Title="Manager" />
    </Columns>
</MudDataGrid>
@code {

    public record Model (string Name, int Age, Severity Status, decimal Salary, DateTime HireDate, bool IsManager);

    ObservableCollection<Model> _items = new ObservableCollection<Model>()
    {
        new Model("Sam", 56, Severity.Normal, 50_000.00M, new DateTime(2005, 3, 5), false), 
        new Model("Alicia", 54, Severity.Info, 75_000.00M, new DateTime(2010, 1, 17), false), 
        new Model("Ira", 27, Severity.Success, 102_000.00M, new DateTime(2017, 6, 15), true),
        new Model("John", 32, Severity.Warning, 132_000.00M, new DateTime(2021, 12, 23), true),
        new Model("Fred", 65, Severity.Warning, 87_000.00M, new DateTime(2003, 7, 3), false), 
        new Model("Tabitha", 33, Severity.Info, 157_000.00M, new DateTime(2015, 2, 12), true), 
        new Model("Hunter", 22, Severity.Success, 43_000.00M, new DateTime(2017, 9, 20), false),
        new Model("Esme", 55, Severity.Warning, 149_000.00M, new DateTime(2017, 8, 1), true)
    };

    void AddItem()
    {
        _items.Add(new Model("New Person", 44, Severity.Warning, 85_000.00M, new DateTime(2022, 1, 1), true));
    }

    void RemoveItem()
    {
        _items.RemoveAt(0);
    }
}
CultureInfo

DataGrid Culture (CultureInfo) property is used to display and editing/filter columns data. Each <Column> can define his own culture, to allow specify its format individually.

Name
Age
Amount (es-ES culture)
Total (invariant culture)
Sam 56 2,3 3.2
Alicia 54 4,5 4.9
Ira 27 2,1 2.5
John 32 5,9 6.1
@using System.Globalization

<MudDataGrid Items="@_items" Filterable="true">
    <Columns>
        <Column T="Model" Field="@nameof(Model.Name)" />
        <Column T="Model" Field="@nameof(Model.Age)" />
        <Column T="Model"
            Field="@nameof(Model.Amount)"
            Title="Amount (es-ES culture)"
            Culture="@(new CultureInfo("es-ES"))" />
        <Column T="Model"
            Field="@nameof(Model.Total)"
            Title="Total (invariant culture)"
            Culture="@CultureInfo.InvariantCulture" />
    </Columns>
</MudDataGrid>
@code {
    private IEnumerable<Model> _items = new List<Model>()
    {
        new Model("Sam", 56, 2.3, 3.2), 
        new Model("Alicia", 54, 4.5, 4.9), 
        new Model("Ira", 27, 2.1, 2.5),
        new Model("John", 32, 5.9, 6.1)
    };

    public record Model(string Name, int? Age, double? Amount, double? Total);
}
An unhandled error has occurred. Reload 🗙