# Table A styled HTML table with a header row, data rows, and optional caption and footer. Use it when you have a list of items with multiple columns — user lists, order history, product inventories. --- ## Quick example ```csharp new Table( headers: new[] { "Name", "Email", "Role" }, rows: users.Select(u => new[] { System.Web.HttpUtility.HtmlEncode(u.DisplayName ?? ""), System.Web.HttpUtility.HtmlEncode(u.Email), u.Role })) ``` --- ## All the options ```csharp public Table( IEnumerable headers, IEnumerable> rows, string caption = "", string footer = "") ``` | Parameter | What it does | |---|---| | `headers` | Column heading strings. | | `rows` | Each inner collection is one table row. Each string in it is a cell. Cells are raw HTML. | | `caption` | Optional summary text displayed below the table. | | `footer` | Optional footer text that spans all columns. | > **HTML safety:** Cell values are inserted as raw HTML. Always use `System.Web.HttpUtility.HtmlEncode()` on any user-supplied strings before passing them in. --- ## Real-world examples ### Table with a count caption and footer note ```csharp new Table( headers: new[] { "Product", "Price", "Stock" }, rows: products.Select(p => new[] { System.Web.HttpUtility.HtmlEncode(p.Name), $"${p.Price:F2}", p.Stock.ToString() }), caption: $"Showing {products.Count} products", footer: "Prices include VAT") ``` ### Status column with a Badge Pre-render the badge to an HTML string and embed it in the cell: ```csharp string RenderBadge(string label, string variant = "default") { var buf = new System.Buffers.ArrayBufferWriter(); new Badge(label, variant).Render(new HtmxRenderContext(buf)); return System.Text.Encoding.UTF8.GetString(buf.WrittenSpan); } new Table( headers: new[] { "Name", "Status" }, rows: users.Select(u => new[] { System.Web.HttpUtility.HtmlEncode(u.DisplayName ?? ""), u.IsActive ? RenderBadge("Active", "default") : RenderBadge("Inactive", "secondary") })) ``` ### Row actions with HTMX edit button ```csharp string EditLink(string id) => $""""""; new Table( headers: new[] { "Name", "" }, rows: users.Select(u => new[] { System.Web.HttpUtility.HtmlEncode(u.DisplayName ?? ""), EditLink(u.Id!) })) ``` --- ## How it works Table wraps a standard `` in an `overflow-auto` container so it scrolls horizontally on small screens. Header cells use `` row. ``` --- ## Tips and tricks - Cells are raw HTML — HTML-encode any user-supplied string values before inserting them to prevent XSS. - Use `System.Web.HttpUtility.HtmlEncode(value)` or `System.Net.WebUtility.HtmlEncode(value)` for any untrusted data. - Pair with `Pagination` below the table for large datasets. - For sortable columns, replace header strings with anchor tags containing HTMX sort-request attributes. - The `footer` string spans all columns — use it for totals, notes, or a "load more" link. - The `footer` string spans all columns — use it for totals, notes, or a "load more" link. --- ## Complete page example **`Templates/AdminUsersPage.htmx`** ```html

Users

$$InviteBtn$$
$$UsersTable$$
``` **`Templates/AdminUsersPage.htmx.cs`** ```csharp namespace Htmx.ApiDemo.Templates; public sealed class AdminUsersPage : AdminUsersPageBase { private readonly IHtmxComponent _table; private readonly IHtmxComponent _invite; public AdminUsersPage(IEnumerable users, int total) { _invite = new Components.Button( "Invite user", variant: "default", extraAttributes: """hx-get="/admin/users/invite" hx-target="#modal" hx-swap="innerHTML" """); var rows = users.Select(u => new[] { System.Net.WebUtility.HtmlEncode(u.DisplayName ?? ""), System.Net.WebUtility.HtmlEncode(u.Email), u.CreatedAt.ToString("yyyy-MM-dd"), $"""""", }); _table = new Components.Table( caption: "All registered accounts", headers: new[] { "Name", "Email", "Joined", "Actions" }, rows: rows, footer: $"{total} users total"); } protected override void RenderInviteBtn(HtmxRenderContext ctx) => _invite.Render(ctx.Next()); protected override void RenderUsersTable(HtmxRenderContext ctx) => _table.Render(ctx.Next()); } ``` **GET handler** ```csharp [Handler] [MapGet("/admin/users")] public static partial class GetAdminUsersHandler { public record Query(); private static async Task HandleAsync( Query _, HttpContext ctx, MongoDbService db, CancellationToken ct) { var users = await db.GetAllUsersAsync(ct); var list = users.ToList(); return await ctx.WriteHtmxPage( new AdminUsersPage(list, list.Count), title: "Admin – Users"); } } ```
` and data cells use ``. The `caption` is rendered inside a `
` element below the table; the `footer` spans all columns in a `