Table
Tables display structured data in rows and columns. Supports static, striped, checkbox, sortable, lazy-loaded, paginated, filtered, and infinite-scroll variants.
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@gmail.com | Silver |
| 2338 | Bob Johnson | johnson.bob@outlook.com | Gold |
| 2342 | Sarah Adams | s.adams@gmail.com | Gold |
@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.
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
| 2345 | Alex Martinez | alex.martinez@penguinui.com | Gold |
| 2346 | Ryan Thompson | ryan.thompson@penguinui.com | Silver |
| 2349 | Emily Rodriguez | emily.rodriguez@penguinui.com | Gold |
@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).
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@gmail.com | |
| 2338 | Bob Johnson | johnson.bob@outlook.com | |
| 2342 | Sarah Adams | s.adams@gmail.com |
@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.
| CustomerID | Name | Membership | ||
|---|---|---|---|---|
| 2335 | Alice Brown | alice.brown@gmail.com | ||
| 2338 | Bob Johnson | johnson.bob@outlook.com | ||
| 2342 | Sarah Adams | s.adams@gmail.com |
@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.
| User | ID | Member Since | Status | Action |
|---|---|---|---|---|
Alice Brown alice.brown@gmail.com | 2335 | Nov 14, 2021 | Active | |
Bob Johnson johnson.bob@penguinui.com | 2338 | Aug 20, 2020 | Active | |
Ryan Thompson ryan.thompson@penguinui.com | 2346 | Feb 5, 2022 | Canceled | |
Emily Rodriguez emily.rodriguez@penguinui.com | 2349 | Jun 14, 2022 | Active | |
Alex Martinez alex.martinez@penguinui.com | 2345 | Sep 17, 2018 | Active |
@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 | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
| 2345 | Alex Martinez | alex.martinez@penguinui.com | Gold |
| 2346 | Ryan Thompson | ryan.thompson@penguinui.com | Silver |
| 2349 | Emily Rodriguez | emily.rodriguez@penguinui.com | Gold |
@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.
| CustomerID | Name | Membership | |
|---|---|---|---|
Loading... | |||
@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.
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
@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 | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
@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.
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
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.
| CustomerID | Name | Membership | |
|---|---|---|---|
| 2335 | Alice Brown | alice.brown@penguinui.com | Silver |
| 2338 | Bob Johnson | johnson.bob@penguinui.com | Gold |
| 2342 | Sarah Adams | s.adams@penguinui.com | Gold |
@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
| Prop | Type | Default | Description |
|---|---|---|---|
Columns | []Column | nil | Column definitions (Key, Label, Sortable, Width, Align). |
Rows | []Row | nil | Row data; each Row.Cells maps a column Key to a Cell (Text or Component). |
Variant | Variant | Default | Style: "default", "striped", or "checkbox". |
ShowCheckbox | bool | false | Adds a leading select column with a header check-all toggle. |
ID | string | "" | Table element id; required for HTMX variants (seeds tbody/paginator ids). |
Caption | string | "" | Optional accessible table caption. |
SortBy | string | "" | Initial sort column key. |
SortDir | SortDir | SortNone | Initial sort direction: "asc", "desc", or "" (none). |
HTMX | *HTMXConfig | nil | Server-side table updates (Endpoint, Target). |
LazyLoad | bool | false | Render a loading tbody that fetches row HTML from HTMX.Endpoint. |
LazyTrigger | string | "load" | HTMX trigger for lazy tbody loading, such as "load" or "click from:#load-lazy-table". |
Pagination | *PaginationConfig | nil | Pagination/infinite-scroll config (CurrentPage, TotalPages, PerPage, Mode, ...). |
Pagination.Mode | PaginationMode | PaginationTraditional | Use PaginationInfiniteScroll to append rows from the sentinel instead of rendering page links. |
Pagination.CurrentPage | int | 0 | Current 1-indexed page for page links and next-page calculations. |
Pagination.TotalPages | int | 0 | Total page count for traditional pagination. |
Pagination.PerPage | int | 0 | Rows requested per page. |
Pagination.HasMore | bool | false | Infinite-scroll sentinel flag; false stops requesting more rows. |
Pagination.ContainerHeight | string | "" | Optional table-local scroll height, such as "400px"; empty uses the nearest page scroller. |
InfiniteScroll | *InfiniteScrollConfig | nil | Deprecated compatibility field; prefer Pagination.Mode: PaginationInfiniteScroll. |
Filters | *FilterConfig | nil | Filter bar config (Variant, Collapsible, Filters[]: search/select/toggle). |
Filters.Variant | FilterVariant | FilterVariantBar | Switches between the bordered/collapsible filter bar and inline filter controls. |
Filters.HTMX | *FilterHTMXConfig | nil | Optional Target and Swap overrides for filter requests; defaults to the table tbody and innerHTML. |
Filter.OptionsHTMX | *FilterOptionsHTMXConfig | nil | Loads select-filter options from a GET endpoint when static Options are not enough. |
ExtraQueryParams | string | "" | Extra query string appended to every HTMX request. |
RootClass | string | "" | Extra classes on the table container. |