Columns
The data grid component provides several column components to define and customize the structure and behavior of your grid. Each column type serves a specific purpose, making it easy to tailor the grid to your needs.
Base
The ColumnBase
is the foundational class for all column components in the data grid.
It provides common properties and functionality that other column types inherit,
serving as the base for custom column implementations.
Template
The TemplateColumn
is a flexible column type not bound to any specific model property.
It uses arbitrary Razor fragments to supply contents for its cells.
It can't infer the column's title or sort order automatically.
Property
The PropertyColumn
is used to bind to a specific property of your data model.
It automatically displays the value of the bound property for each row.
This column infers sorting rules automatically,
and uses the property's name as its title if not otherwise set.
Edit
The EditColumn
extends the functionality of PropertyColumn
by enabling incell editing.
This column type is ideal for editable grids where users need to update data directly.
Usage
The data grid component provides a powerful way to display and manage large sets of data.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Loading
Indicate a loading state while data is being fetched, displaying a loading message or spinner.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
Loading... |
<LumexDataGrid Data="@_users" Loading="@true">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Hoverable
Enable hover effects on rows to enhance visual feedback during interaction.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users" Hoverable="@true">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Striped
Alternate row colors for better readability in large datasets.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users" Striped="@true">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Sticky Header
Keep the header fixed at the top as users scroll through data.
Name | Role | Status |
---|---|---|
Alice Johnson | Admin | Active |
Bob Smith | Moderator | Inactive |
Carol Brown | User | Pending |
David Wilson | Admin | Active |
Eve Davis | User | Banned |
Frank Miller | Moderator | Active |
Grace Hall | User | Active |
Hank Lee | Admin | Pending |
Ivy Clark | User | Inactive |
Jack White | Moderator | Banned |
Kathy Young | Admin | Active |
Leo King | User | Pending |
Mona Baker | Moderator | Active |
Nate Adams | User | Banned |
Olive Moore | Admin | Inactive |
Paul Harris | User | Active |
Quincy Evans | Moderator | Pending |
Rita Torres | Admin | Banned |
Sam Ramirez | User | Inactive |
Tina Perez | Moderator | Active |
<LumexDataGrid Data="@_users"
StickyHeader="@true"
Class="max-h-64">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new("Alice Johnson", "Admin", "Active"),
new("Bob Smith", "Moderator", "Inactive"),
new("Carol Brown", "User", "Pending"),
new("David Wilson", "Admin", "Active"),
new("Eve Davis", "User", "Banned"),
new("Frank Miller", "Moderator", "Active"),
new("Grace Hall", "User", "Active"),
new("Hank Lee", "Admin", "Pending"),
new("Ivy Clark", "User", "Inactive"),
new("Jack White", "Moderator", "Banned"),
new("Kathy Young", "Admin", "Active"),
new("Leo King", "User", "Pending"),
new("Mona Baker", "Moderator", "Active"),
new("Nate Adams", "User", "Banned"),
new("Olive Moore", "Admin", "Inactive"),
new("Paul Harris", "User", "Active"),
new("Quincy Evans", "Moderator", "Pending"),
new("Rita Torres", "Admin", "Banned"),
new("Sam Ramirez", "User", "Inactive"),
new("Tina Perez", "Moderator", "Active")
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Radius
Adjust border radius for a more rounded or square appearance.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users" Radius="@_radius">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
<fieldset class="flex gap-4">
@foreach( var radius in _radiuses )
{
var value = radius.ToString();
<div class="flex gap-1">
<input type="radio"
id="@($"radius-{value.ToLower()}")"
name="radius"
@bind:event="onchange"
@bind:get="@radius"
@bind:set="@OnRadiusSelect" />
<label for="@($"radius-{value.ToLower()}")">@value</label>
</div>
}
</fieldset>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private readonly Radius[] _radiuses = [
Radius.None,
Radius.Small,
Radius.Medium,
Radius.Large
];
private Radius _radius = Radius.Small;
private void OnRadiusSelect( Radius value )
{
_radius = value;
}
private record User( string Name, string Role, string Status );
}
Shadows
Add shadows for an elevated, visually distinct look.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users" Shadow="@_shadow">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
<fieldset class="flex gap-4">
@foreach( var shadow in _shadows )
{
var value = shadow.ToString();
<div class="flex gap-1">
<input type="radio"
id="@($"shadow-{value.ToLower()}")"
name="shadow"
@bind:event="onchange"
@bind:get="@shadow"
@bind:set="@OnShadowSelect" />
<label for="@($"shadow-{value.ToLower()}")">@value</label>
</div>
}
</fieldset>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private readonly Shadow[] _shadows = [
Shadow.None,
Shadow.Small,
Shadow.Medium,
Shadow.Large
];
private Shadow _shadow = Shadow.Small;
private void OnShadowSelect( Shadow value )
{
_shadow = value;
}
private record User( string Name, string Role, string Status );
}
Table Layout
Choose between different table layouts,
such as Fixed
or Auto
.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users" Layout="@Layout.Fixed">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Disabled Items
Mark specific rows as disabled to prevent interactions on them.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users"
DisabledItems="@DisabledUsers">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private ICollection<User> DisabledUsers =>
_users.Where( u => u.Status == "Inactive" ).ToList();
private record User( string Name, string Role, string Status );
}
Selected Items
Single Selection
The data grid supports single selection mode, allowing users to select one row at a time.
Name | Role | Status | |
---|---|---|---|
Alice Johnson | Administrator | Active | |
Bob Smith | Editor | Inactive | |
Charlie Brown | Viewer | Pending | |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users"
Color="@_color"
SelectionMode="@SelectionMode.Single"
@bind-SelectedItems="@_selectedUsers">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
<fieldset class="flex gap-4">
@foreach( var color in _colors )
{
var value = color.ToString();
<div class="flex gap-1">
<input type="radio"
id="@($"single-sel-{value.ToLower()}")"
name="color"
@bind:event="onchange"
@bind:get="@color"
@bind:set="@OnColorSelect" />
<label for="@($"single-sel-{value.ToLower()}")">@value</label>
</div>
}
</fieldset>
@if( _selectedUsers.Count > 0 )
{
<div class="text-small">
<p>Selected user:</p>
<ul>
@foreach( var user in _selectedUsers )
{
<li>@user</li>
}
</ul>
</div>
}
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private readonly ThemeColor[] _colors = [
ThemeColor.Default,
ThemeColor.Primary,
ThemeColor.Secondary,
ThemeColor.Success,
ThemeColor.Warning,
ThemeColor.Danger,
ThemeColor.Info
];
private ThemeColor _color = ThemeColor.Default;
private ICollection<User> _selectedUsers = [];
private void OnColorSelect( ThemeColor value )
{
_color = value;
}
private record User( string Name, string Role, string Status );
}
Multiple Selection
The data grid also supports multiple selection mode, enabling users to select multiple rows simultaneously.
Name | Role | Status | |
---|---|---|---|
Alice Johnson | Administrator | Active | |
Bob Smith | Editor | Inactive | |
Charlie Brown | Viewer | Pending | |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users"
Color="@_color"
SelectionMode="@SelectionMode.Multiple"
@bind-SelectedItems="@_selectedUsers">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
<fieldset class="flex gap-4">
@foreach( var color in _colors )
{
var value = color.ToString();
<div class="flex gap-1">
<input type="radio"
id="@($"multiple-sel-{value.ToLower()}")"
name="color"
@bind:event="onchange"
@bind:get="@color"
@bind:set="@OnColorSelect" />
<label for="@($"multiple-sel-{value.ToLower()}")">@value</label>
</div>
}
</fieldset>
@if( _selectedUsers.Count > 0 )
{
<div class="text-small">
<p>Selected users:</p>
<ul>
@foreach( var user in _selectedUsers )
{
<li>@user</li>
}
</ul>
</div>
}
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private readonly ThemeColor[] _colors = [
ThemeColor.Default,
ThemeColor.Primary,
ThemeColor.Secondary,
ThemeColor.Success,
ThemeColor.Warning,
ThemeColor.Danger,
ThemeColor.Info
];
private ThemeColor _color = ThemeColor.Default;
private ICollection<User> _selectedUsers = [];
private void OnColorSelect( ThemeColor value )
{
_color = value;
}
private record User( string Name, string Role, string Status );
}
A checkbox column automatically appears as the first column for easy row selection, alongside row selection on click.
Editing
Allow incell editing for easy data updates
directly within the grid using EditColumn
.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<EditColumn Property="@(p => p.Name)" />
<EditColumn Property="@(p => p.Role)" />
<EditColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Sorting
Enable sorting by column headers to arrange data in ascending or descending order.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" Sortable="@true" />
<PropertyColumn Property="@(p => p.Role)" Sortable="@true" />
<PropertyColumn Property="@(p => p.Status)" Sortable="@true" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Virtualization
Optimize performance by loading only the rows visible within the viewport.
ID | State | City | Company | Status |
---|---|---|---|---|
26636 results found
@inject HttpClient HttpClient
@inject NavigationManager NavigationManager
<LumexDataGrid DataSource="@_foodRecallProvider"
ItemSize="48"
Virtualize="@true"
StickyHeader="@true"
Class="max-h-64">
<PropertyColumn Property="@(p => p.Event_Id)" Title="ID" />
<PropertyColumn Property="@(p => p.State)" />
<PropertyColumn Property="@(p => p.City)" />
<PropertyColumn Property="@(p => p.Recalling_Firm)" Title="Company" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
<p class="text-small">
<strong>@_resultsCount results found</strong>
</p>
@code {
private DataSource<FoodRecall>? _foodRecallProvider;
private int _resultsCount;
protected override async Task OnInitializedAsync()
{
_foodRecallProvider = async req =>
{
var url = NavigationManager.GetUriWithQueryParameters( "https://api.fda.gov/food/enforcement.json", new Dictionary<string, object?>
{
{ "skip", req.StartIndex },
{ "limit", req.Count },
} );
var response = await HttpClient.GetFromJsonAsync<FoodRecallQueryResult>( url, req.CancellationToken );
return DataSourceResult.From(
items: response!.Results,
totalItemCount: response!.Meta.Results.Total );
};
_resultsCount = ( await HttpClient.GetFromJsonAsync<FoodRecallQueryResult>( "https://api.fda.gov/food/enforcement.json" ) )!.Meta.Results.Total;
}
private class FoodRecall
{
public string Status { get; set; } = default!;
public string City { get; set; } = default!;
public string State { get; set; } = default!;
public string Recalling_Firm { get; set; } = default!;
public string Event_Id { get; set; } = default!;
}
private class FoodRecallQueryResult
{
public FoodRecall[] Results { get; set; } = default!;
public FoodRecallMeta Meta { get; set; } = default!;
public class FoodRecallMeta
{
public MetaResults Results { get; set; } = default!;
public record MetaResults( int Skip, int Limit, int Total );
}
}
}
For virtualization to work properly and reliably, you must ensure that every row renders with the same known height. Otherwise, scrolling will behave erratically.
Custom Cells
Customize individual column cells to display specific
content or styles using the Content
parameter.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)">
<Content>
@{
var status = context.Status;
<span class="px-1.5 py-0.5 text-tiny rounded-full @(_statusVariants[status])">@status</span>
}
</Content>
</PropertyColumn>
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private readonly Dictionary<string, string> _statusVariants = new()
{
["Pending"] = "border border-primary-300 bg-primary-50 text-primary",
["Active"] = "border border-danger-300 bg-danger-50 text-danger",
["Inactive"] = "border border-default-300 bg-default-100 text-default-500"
};
private record User( string Name, string Role, string Status );
}
Alternatively, you can provide an arbitrary content to
the TemplateColumn
, such as action buttons.
Name | Role | Status | Actions |
---|---|---|---|
Alice Johnson | Administrator | Active | |
Bob Smith | Editor | Inactive | |
Charlie Brown | Viewer | Pending | |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
<TemplateColumn Title="Actions" Align="@Align.Center">
<LumexButton Size="@Size.Small"
Variant="@Variant.Light"
Class="min-w-8 w-8 h-8 px-0">
<LumexIcon Icon="@Icons.Rounded.MoreVert"
Color="@ThemeColor.None"
Class="text-default-500" />
</LumexButton>
</TemplateColumn>
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Rendering numerous components or event handlers can affect grid performance. Mitigate this by using pagination or virtualization to reduce the number of components displayed at a time.
Custom Format
The data grid allows you to define custom formatting for column values, enabling you to display data in a specific way, such as formatting dates, numbers, or strings.
Name | Role | Salary | Status |
---|---|---|---|
Alice Johnson | Administrator | $3,000 | Active |
Bob Smith | Editor | $2,000 | Inactive |
Charlie Brown | Viewer | $1,500 | Pending |
Diana Lee | Moderator | $2,500 | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Salary)" Format="C0" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", 3000, "Active" ),
new( "Bob Smith", "Editor", 2000, "Inactive" ),
new( "Charlie Brown", "Viewer", 1500, "Pending" ),
new( "Diana Lee", "Moderator", 2500, "Active" )
}.AsQueryable();
private record User( string Name, string Role, decimal Salary, string Status );
}
Dynamic Columns
The data grid supports dynamic columns, allowing you to show or hide columns based on runtime conditions for a flexible and responsive layout.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@_users">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" Visible="@_isRoleColShown" />
<PropertyColumn Property="@(p => p.Status)" Visible="@_isStatusColShown" />
</LumexDataGrid>
<LumexCheckboxGroup Label="Select columns to show"
Classes="@(new() { Wrapper = "flex-row" })">
<LumexCheckbox @bind-Value="@_isRoleColShown">Role</LumexCheckbox>
<LumexCheckbox @bind-Value="@_isStatusColShown">Status</LumexCheckbox>
</LumexCheckboxGroup>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private bool _isRoleColShown = true;
private bool _isStatusColShown = true;
private record User( string Name, string Role, string Status );
}
Header Content
The data grid allows a complete replacement of the default header cell contents.
Name | Role | STATUS
|
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@FilteredUsers"
Layout="@Layout.Fixed"
Classes="@(new() { Table = "w-full" })">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" HeaderContent="@HeaderContent" />
</LumexDataGrid>
@code {
private RenderFragment<LumexColumnBase<User>> HeaderContent => context =>
@<div class="flex items-center gap-2">
@context.Title?.ToUpperInvariant()
<LumexPopover Offset="2"
Radius="@Radius.Small"
Placement="@PopoverPlacement.BottomEnd">
<LumexPopoverTrigger Size="@Size.Small"
Variant="@Variant.Flat"
Class="min-w-8 w-8 h-8 px-0 hover:bg-none">
<LumexIcon Icon="@Icons.Rounded.Tune"
Size="@new("20")"
Color="@ThemeColor.Default" />
</LumexPopoverTrigger>
<LumexPopoverContent>
<LumexTextbox Autofocus="@true"
Size="@Size.Small"
Color="@ThemeColor.Primary"
Variant="@InputVariant.Underlined"
Behavior="@InputBehavior.OnInput"
Placeholder="Status..."
@bind-Value="@_statusFilter" />
</LumexPopoverContent>
</LumexPopover>
</div>;
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private string? _statusFilter;
private IQueryable<User> FilteredUsers
{
get
{
var result = _users;
if( !string.IsNullOrEmpty( _statusFilter ) )
{
result = result.Where( u => u.Status.Contains( _statusFilter, StringComparison.CurrentCultureIgnoreCase ) );
}
return result;
}
}
private record User( string Name, string Role, string Status );
}
Empty Content
The data grid allows you to define custom content or messages that display when there is no data to show.
Name | Role | Status |
---|---|---|
\(o_o)/
No records found |
<LumexDataGrid Data="@_users" EmptyContent="@_emptyContent">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly RenderFragment _emptyContent =
@<div class="flex flex-col space-y-2">
<span class="text-3xl">\(o_o)/</span>
<span>No records found</span>
</div>;
private readonly IQueryable<User> _users = Array.Empty<User>().AsQueryable();
private record User( string Name, string Role, string Status );
}
Loading Content
The data grid component allows you to display custom loading content, giving users a visual cue while data is being fetched or processed.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
Fetching data... |
<LumexDataGrid Data="@_users"
Loading="@true"
LoadingContent="@_loadingContent">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@code {
private readonly RenderFragment _loadingContent =
@<text>
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-indigo-500"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4" />
<path class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
Fetching data...
</text>;
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private record User( string Name, string Role, string Status );
}
Toolbar Content
Add a toolbar with custom actions or filters above the grid.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid Data="@FilteredUsers">
<ToolbarContent>
<div>
<LumexTextbox Placeholder="Search by name..."
Behavior="@InputBehavior.OnInput"
Class="max-w-xs"
@bind-Value="@_nameFilter">
<StartContent>
<LumexIcon Icon="@Icons.Rounded.Search"
Size="@new("20")"
Color="@ThemeColor.Default" />
</StartContent>
</LumexTextbox>
</div>
</ToolbarContent>
<ChildContent>
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</ChildContent>
</LumexDataGrid>
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private string? _nameFilter;
private IQueryable<User> FilteredUsers
{
get
{
var result = _users;
if( !string.IsNullOrEmpty( _nameFilter ) )
{
result = result.Where( u => u.Name.Contains( _nameFilter, StringComparison.CurrentCultureIgnoreCase ) );
}
return result;
}
}
private record User( string Name, string Role, string Status );
}
Remote Data
Fetch data from an external source to populate the grid.
Name | Height | Mass |
---|---|---|
Luke Skywalker | 172 | 77 |
C-3PO | 167 | 75 |
R2-D2 | 96 | 32 |
Darth Vader | 202 | 136 |
Leia Organa | 150 | 49 |
Owen Lars | 178 | 120 |
Beru Whitesun lars | 165 | 75 |
R5-D4 | 97 | 32 |
Biggs Darklighter | 183 | 84 |
Obi-Wan Kenobi | 182 | 77 |
@inject HttpClient HttpClient
<LumexDataGrid DataSource="@_peopleProvider">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Height)" />
<PropertyColumn Property="@(p => p.Mass)" />
</LumexDataGrid>
@code {
private DataSource<Person>? _peopleProvider;
protected override void OnInitialized()
{
_peopleProvider = async req =>
{
var response = await HttpClient.GetFromJsonAsync<PersonQueryResult>( "https://swapi.py4e.com/api/people/", req.CancellationToken );
return DataSourceResult.From(
items: response!.Results,
totalItemCount: response!.Results.Length );
};
}
private record Person( string Name, string Height, string Mass );
private record PersonQueryResult( int Count, string Next, string Previous, Person[] Results );
}
It's only possible to perform data operations, such as sorting, filtering, or others, that are supported by the external API.
Row Click
The data grid exposes an OnRowClick
event,
triggered whenever a row is clicked.
Name | Role | Status |
---|---|---|
Alice Johnson | Administrator | Active |
Bob Smith | Editor | Inactive |
Charlie Brown | Viewer | Pending |
Diana Lee | Moderator | Active |
<LumexDataGrid T="User"
Data="@_users"
OnRowClick="@OnRowClickHandler">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Role)" />
<PropertyColumn Property="@(p => p.Status)" />
</LumexDataGrid>
@if( _clickedRow is not null )
{
<div class="text-small">
<p>Row data: @_clickedRow.Item</p>
<p>Row index: @_clickedRow.Index</p>
</div>
}
@code {
private readonly IQueryable<User> _users = new List<User>
{
new( "Alice Johnson", "Administrator", "Active" ),
new( "Bob Smith", "Editor", "Inactive" ),
new( "Charlie Brown", "Viewer", "Pending" ),
new( "Diana Lee", "Moderator", "Active" )
}.AsQueryable();
private DataGridRowClickEventArgs<User>? _clickedRow;
private void OnRowClickHandler( DataGridRowClickEventArgs<User> args )
{
_clickedRow = args;
}
private record User( string Name, string Role, string Status );
}
Custom Styles
This component suppots named slots (represented as data-*
attributes) that
allow you to apply custom CSS to specific parts of the component.
- Root: The base container of the data grid.
- Wrapper: The wrapper element that surrounds the data grid.
- EmptyWrapper: The wrapper of a content displayed when the data grid is empty.
- LoadingWrapper: The wrapper of a content displayed while the data grid is loading.
- Table: The table element within the data grid.
- Thead: The table header element (thead) in the data grid.
- Tbody: The table body element (tbody) in the data grid.
- Tfoot: The table footer element (tfoot) in the data grid.
- Tr: The table row element (tr) in the data grid.
- Th: The table header cell (th) in the data grid.
- Td: The table data cell (td) in the data grid.
- Placeholder: The placeholder content displayed in the virtualized data grid.
- SortIcon: The sort icon displayed in the header of sortable columns.
You can customize the component(s) by passing any Tailwind CSS classes to the following component parameters:
DataGrid
Class
: The CSS class names for the base container of the data grid.Classes
: The CSS class names for the data grid slots.
API
See the API references below for a complete guide to all the parameters available for the components mentioned here.