N

Server-side sort

Sortable column headers whose href encodes the sort state. Click to toggle; the server is the source of truth.

#When to use

Tables where the dataset is too large to sort in memory, or where the sort key is a computed column. For small, purely client-visible sorts, consider Alpine's Array.prototype.sort over the bound array instead.

#Markup

html
<th>
    <a hx-get="/products?sort=price&dir=@(ViewData["NextDir"])"
       hx-target="#products_table"
       hx-swap="outerHTML"
       hx-push-url="true"
       href="/products?sort=price&dir=@(ViewData["NextDir"])">
        Price
        @if (ViewData["Sort"] as string == "price")
        {
            <span>@(ViewData["Dir"] as string == "asc" ? "▲" : "▼")</span>
        }
    </a>
</th>

hx-push-url="true" keeps the URL in sync so the sort state survives refresh and back-navigation.

#Handler

csharp
public async Task<IActionResult> OnGetAsync(string sort = "name", string dir = "asc")
{
    var results = await _products.ListAsync(sort, dir);
    ViewData["Sort"] = sort;
    ViewData["Dir"] = dir;
    ViewData["NextDir"] = dir == "asc" ? "desc" : "asc";
    return this.PageOrPartial("_ProductsTable", results);
}

#DataTable component

The ndui add datatable component wires this pattern end-to-end — column header, toggle, htmx target, and pagination — from a handful of parameters. See components/datatable.