Table

Tables display structured data in rows and columns. Supports static, striped, checkbox, sortable, lazy-loaded, paginated, filtered, and infinite-scroll variants.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@gmail.comSilver
2338Bob Johnsonjohnson.bob@outlook.comGold
2342Sarah Adamss.adams@gmail.comGold
Usage Example
@table.Table(table.Config{
    Columns: []table.Column{
        {Key: "id", Label: "CustomerID"},
        {Key: "name", Label: "Name"},
        {Key: "email", Label: "Email"},
        {Key: "membership", Label: "Membership"},
    },
    Rows: rows,
})

Striped Table

Set Variant: table.Striped to zebra-stripe the rows.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
2345Alex Martinezalex.martinez@penguinui.comGold
2346Ryan Thompsonryan.thompson@penguinui.comSilver
2349Emily Rodriguezemily.rodriguez@penguinui.comGold
Striped Table
@table.Table(table.Config{
    Variant: table.Striped,
    Columns: columns,
    Rows:    rows,
})

Table with Action

Render an interactive control in a cell via Cell.Component (e.g. table.ActionButton).

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@gmail.com
2338Bob Johnsonjohnson.bob@outlook.com
2342Sarah Adamss.adams@gmail.com
Table with Action
@table.Table(table.Config{
    Columns: actionColumns(),
    Rows: []table.Row{
        {ID: "2335", Cells: map[string]table.Cell{
            "id":     {Text: "2335"},
            "name":   {Text: "Alice Brown"},
            "email":  {Text: "alice.brown@gmail.com"},
            "action": {Component: table.ActionButton("Edit")},
        }},
    },
})

Table with Checkbox

Set ShowCheckbox: true to add a select column with a header check-all toggle.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@gmail.com
2338Bob Johnsonjohnson.bob@outlook.com
2342Sarah Adamss.adams@gmail.com
Table with Checkbox
@table.Table(table.Config{
    ShowCheckbox: true,
    Columns:      actionColumns(),
    Rows:         rows,
})

Users Table

Compose rich cells: table.ImageCell (image + label + detail), table.StatusBadge, and table.ActionButton.

UserIDMember SinceStatusAction
Alice Brown
Alice Brown alice.brown@gmail.com
2335Nov 14, 2021Active
Bob Johnson
Bob Johnson johnson.bob@penguinui.com
2338Aug 20, 2020Active
Ryan Thompson
Ryan Thompson ryan.thompson@penguinui.com
2346Feb 5, 2022Canceled
Emily Rodriguez
Emily Rodriguez emily.rodriguez@penguinui.com
2349Jun 14, 2022Active
Alex Martinez
Alex Martinez alex.martinez@penguinui.com
2345Sep 17, 2018Active
Users Table
@table.Table(table.Config{
    Columns: usersColumns(),
    Rows: []table.Row{
        {ID: "2335", Cells: map[string]table.Cell{
            "user":   {Component: table.ImageCell("/.../avatar-8.webp", "Alice Brown", "alice.brown@gmail.com")},
            "id":     {Text: "2335"},
            "since":  {Text: "Nov 14, 2021"},
            "status": {Component: table.StatusBadge("Active", "success")},
            "action": {Component: table.ActionButton("Edit")},
        }},
    },
})

Sortable Table (HTMX)

Mark columns Sortable: true and set HTMX.Endpoint. Clicking a header cycles neutral → asc → desc and fetches sorted rows from the server.

CustomerID
Name
Email
Membership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
2345Alex Martinezalex.martinez@penguinui.comGold
2346Ryan Thompsonryan.thompson@penguinui.comSilver
2349Emily Rodriguezemily.rodriguez@penguinui.comGold
Sortable Table (HTMX)
@table.Table(table.Config{
    ID:           "sortable-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows"},
    SortBy:       "id",
    SortDir:      table.SortAsc,
    Columns: []table.Column{
        {Key: "id", Label: "CustomerID", Sortable: true},
        {Key: "name", Label: "Name", Sortable: true},
        {Key: "email", Label: "Email"},
        {Key: "membership", Label: "Membership", Sortable: true},
    },
    Rows: rows,
})

Lazy-Loaded Table

Set LazyLoad: true to render a loading tbody, then choose when HTMX fetches rows. The default trigger is page load; this example waits for a button click.

The table renders its headers first. Rows are fetched only after you request them.

CustomerIDNameEmailMembership
Loading...
Lazy-Loaded Table
@table.Table(table.Config{
    ID:           "lazy-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows?variant=lazy"},
    LazyLoad:     true,
    LazyTrigger:  "click from:#load-lazy-table",
    Columns:      columns,
})

Paginated Table

Pass a Pagination config; Prev/Next and page links swap the tbody and paginator via HTMX OOB.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
Page 1 of 4
Paginated Table
@table.Table(table.Config{
    ID:           "paginated-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows"},
    Columns:      columns,
    Rows:         pageRows(1),
    Pagination:   &table.PaginationConfig{CurrentPage: 1, TotalPages: 4, PerPage: 3},
})

Filtered Table

Add a Filters config with search/select/toggle filters. The bar variant renders a collapsible bordered block.

CustomerID
Name
Email
Membership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
Page 1 of 4
Filtered Table
@table.Table(table.Config{
    ID:           "filtered-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows"},
    Columns:      sortableColumns(),
    Rows:         pageRows(1),
    Pagination:   &table.PaginationConfig{CurrentPage: 1, TotalPages: 4, PerPage: 3},
    Filters: &table.FilterConfig{
        Collapsible:       true,
        InitiallyExpanded: true,
        Filters: []table.Filter{
            {Key: "search", Label: "Search", Type: table.FilterSearch, Placeholder: "Search by name or email..."},
            {Key: "membership", Label: "Membership", Type: table.FilterSelect, Options: memberships},
        },
    },
})

Inline Filter Variant

Set Filters.Variant: table.FilterVariantInline for the same controls without the bordered block or collapsible toggle — suited to modal bodies and toolbar strips.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
Page 1 of 4
Inline Filter Variant
Filters: &table.FilterConfig{
    Variant: table.FilterVariantInline,
    Filters: []table.Filter{
        {Key: "search", Type: table.FilterSearch, Placeholder: "Search…"},
        {Key: "membership", Type: table.FilterSelect, Options: memberships},
    },
}

Infinite Scroll Table

Use Pagination.Mode: table.PaginationInfiniteScroll. By default the sentinel watches the page scroller; set Pagination.ContainerHeight only when the table needs its own capped scroll area.

CustomerIDNameEmailMembership
2335Alice Brownalice.brown@penguinui.comSilver
2338Bob Johnsonjohnson.bob@penguinui.comGold
2342Sarah Adamss.adams@penguinui.comGold
Infinite Scroll Table
@table.Table(table.Config{
    ID:           "infinite-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows?variant=infinite"},
    Columns:      columns,
    Rows:         initialRows,
    Pagination: &table.PaginationConfig{
        Mode:            table.PaginationInfiniteScroll,
        CurrentPage:     1,
        PerPage:         3,
        HasMore:         true,
        ContainerHeight: "300px",
    },
})

API Reference

PropTypeDefaultDescription
Columns[]ColumnnilColumn definitions (Key, Label, Sortable, Width, Align).
Rows[]RownilRow data; each Row.Cells maps a column Key to a Cell (Text or Component).
VariantVariantDefaultStyle: "default", "striped", or "checkbox".
ShowCheckboxboolfalseAdds a leading select column with a header check-all toggle.
IDstring""Table element id; required for HTMX variants (seeds tbody/paginator ids).
Captionstring""Optional accessible table caption.
SortBystring""Initial sort column key.
SortDirSortDirSortNoneInitial sort direction: "asc", "desc", or "" (none).
HTMX*HTMXConfignilServer-side table updates (Endpoint, Target).
LazyLoadboolfalseRender a loading tbody that fetches row HTML from HTMX.Endpoint.
LazyTriggerstring"load"HTMX trigger for lazy tbody loading, such as "load" or "click from:#load-lazy-table".
Pagination*PaginationConfignilPagination/infinite-scroll config (CurrentPage, TotalPages, PerPage, Mode, ...).
Pagination.ModePaginationModePaginationTraditionalUse PaginationInfiniteScroll to append rows from the sentinel instead of rendering page links.
Pagination.CurrentPageint0Current 1-indexed page for page links and next-page calculations.
Pagination.TotalPagesint0Total page count for traditional pagination.
Pagination.PerPageint0Rows requested per page.
Pagination.HasMoreboolfalseInfinite-scroll sentinel flag; false stops requesting more rows.
Pagination.ContainerHeightstring""Optional table-local scroll height, such as "400px"; empty uses the nearest page scroller.
InfiniteScroll*InfiniteScrollConfignilDeprecated compatibility field; prefer Pagination.Mode: PaginationInfiniteScroll.
Filters*FilterConfignilFilter bar config (Variant, Collapsible, Filters[]: search/select/toggle).
Filters.VariantFilterVariantFilterVariantBarSwitches between the bordered/collapsible filter bar and inline filter controls.
Filters.HTMX*FilterHTMXConfignilOptional Target and Swap overrides for filter requests; defaults to the table tbody and innerHTML.
Filter.OptionsHTMX*FilterOptionsHTMXConfignilLoads select-filter options from a GET endpoint when static Options are not enough.
ExtraQueryParamsstring""Extra query string appended to every HTMX request.
RootClassstring""Extra classes on the table container.