Data Grid

Display typed data with columns, sorting, selection, and pagination.

The data grid is part of StellarAdmin.TagHelpers and uses the standard tag helper setup, theme stylesheet, and JavaScript bundle.

Setup

Register the tag helpers alongside your application's MVC or Razor Pages services:

builder.Services.AddStellarAdmin().AddTagHelpers();

Add these directives to _ViewImports.cshtml:

@using StellarAdmin.TagHelpers
@addTagHelper *, StellarAdmin.TagHelpers

Example

    var selectedPageSize = int.TryParse(Context.Request.Query["pageSize"], out var requestedPageSize)
        ? (int?)Math.Max(requestedPageSize, 1)
        : null;
    var pageSize = selectedPageSize ?? 3;
    var pageNo = int.TryParse(Context.Request.Query["pageNo"], out var requestedPage)
        ? Math.Max(requestedPage, 1)
        : 1;
    var sortBy = Context.Request.Query["sortBy"].ToString();
    var sortDirection = Context.Request.Query["sortDir"] == "desc"
        ? DataGridSortDirection.Descending
        : DataGridSortDirection.Ascending;

    IEnumerable<Booking> bookings = StaticData.Bookings;
    bookings = (sortBy.ToLowerInvariant(), sortDirection) switch
    {
        ("destination", DataGridSortDirection.Ascending) => bookings.OrderBy(b => b.Destination),
        ("destination", DataGridSortDirection.Descending) => bookings.OrderByDescending(b => b.Destination),
        ("amount", DataGridSortDirection.Ascending) => bookings.OrderBy(b => b.Amount),
        ("amount", DataGridSortDirection.Descending) => bookings.OrderByDescending(b => b.Amount),
        _ => bookings
    };
    var pageOfBookings = bookings.Skip((pageNo - 1) * pageSize).Take(pageSize);
    var totalPages = (int)Math.Ceiling(StaticData.Bookings.Length / (double)pageSize);
}
<sa-data-grid items="pageOfBookings">
    <sa-data-grid-selection key-field="Id" name="selectedBookings" id="booking-grid-selection"/>
    <sa-data-grid-sort sort-by="@sortBy" sort-direction="sortDirection"
                       asp-page="/DataGrid/Index"
                       asp-route-sortBy="{sort}" asp-route-sortDir="{dir}"
                       preserve-query="true" preserve-query-except="pageNo"/>
    <sa-data-grid-column title="Booking #" field="Id" class="font-medium"/>
    <sa-data-grid-column title="Status" field="Status"/>
    <sa-data-grid-column title="Destination" field="Destination" sortable="true"/>
    <sa-data-grid-column title="Amount" field="Amount" format="{0:C}" sortable="true" class="text-right"/>
    <sa-data-grid-empty>No bookings found.</sa-data-grid-empty>
    <sa-data-grid-pager page-no="pageNo" total-pages="totalPages"
                        page-size="pageSize" selected-page-size="selectedPageSize"
                        total-items="StaticData.Bookings.Length"
                        page-size-options="3,5,10"
                        asp-page="/DataGrid/Index"
                        asp-route-pageNo="{pageNo}" asp-route-pageSize="{pageSize}"
                        preserve-query="true"/>
</sa-data-grid>
<sa-button id="booking-grid-delete" variant="ButtonVariant.Destructive" class="mt-4" hidden>
    Delete selected
</sa-button>
<script>
    (() => {
        const selection = document.getElementById("booking-grid-selection");
        const deleteButton = document.getElementById("booking-grid-delete");

        const syncButton = () => deleteButton.hidden = selection.selectedValues.length === 0;

        selection.addEventListener("selection-change", syncButton);
        customElements.whenDefined("sel-table-selection").then(syncButton);

        deleteButton.addEventListener("click", () =>
            alert(`Delete bookings:\n${selection.selectedValues.join("\n")}`));
    })();
</script>

Selection works in this static preview. Sorting and pagination are disabled in the static preview and require the running DocsSamples app at /DataGrid; the sample reads query parameters and applies sorting and paging on the server. Supply the current page of items to sa-data-grid, define columns with sa-data-grid-column, and provide sorting and pagination state through the corresponding child tags.

Row details

Add an <sa-data-grid-row-detail> to let rows expand and show more information below them. Its content is a row template like a column's <sa-data-grid-item-template>: it renders once per row, with the row's item available through Html.GridItem<T>(), so the details can show more fields of the same item or rows from another source, such as the itinerary in a nested grid here. The grid adds a column of toggles, with an expand-all toggle in its header. To render rows expanded, set key-field to the property that identifies a row and expanded-keys to the keys of the rows to open.

<sa-data-grid items="StaticData.Bookings" class="w-full">
    <sa-data-grid-column title="Booking #" field="Id" class="font-medium"/>
    <sa-data-grid-column title="Status" field="Status"/>
    <sa-data-grid-column title="Destination" field="Destination"/>
    <sa-data-grid-column title="Amount" field="Amount" format="{0:C}" class="text-right"/>
    <sa-data-grid-row-detail key-field="Id" expanded-keys='new[] { "TRP-4821" }'>
        @{ var details = StaticData.DetailsFor(Html.GridItem<Booking>().Id); }
        <div class="flex flex-col gap-3">
            <p>
                <span class="font-medium">@details.Traveller</span>
                <span class="text-muted-foreground">· @details.Party · @details.Email</span>
            </p>
            <sa-data-grid items="details.Itinerary">
                <sa-data-grid-column title="Date" field="Date"/>
                <sa-data-grid-column title="Type" field="Type"/>
                <sa-data-grid-column title="Description" field="Description"/>
                <sa-data-grid-column title="Amount" field="Amount" class="text-right"/>
            </sa-data-grid>
        </div>
    </sa-data-grid-row-detail>
</sa-data-grid>

The details use the same behavior and events as table row details, including loading them with htmx. To place the toggle yourself, such as in an actions column beside an edit button, set toggle="DataGridRowDetailToggle.None" and add an <sa-table-row-detail-toggle> to that column's <sa-data-grid-item-template>. The emphasis, divider and inset settings look as they do on a table; see the row details divider example.

<sa-data-grid-row-detail>

Prop

Type

On this page