Skip to content

Table

Tables display structured data in rows and columns, with optional striping, row selection, sorting, lazy loading, pagination, filters, and infinite scroll.

Default Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
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 Appearance: table.AppearanceStriped to zebra-stripe the rows.

Striped Table Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
2345Alex Martinez[email protected]Gold
2346Ryan Thompson[email protected]Silver
2349Emily Rodriguez[email protected]Gold
Striped Table
@table.Table(table.Config{
    Appearance: table.AppearanceStriped,
    Columns: columns,
    Rows:    rows,
})

Table with Action

Render an interactive control in a cell via Cell.Component (e.g. button.Button).

Table with Action Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]
2338Bob Johnson[email protected]
2342Sarah Adams[email protected]
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: "[email protected]"},
            "action": {Component: tableEditButton()},
        }},
    },
})

Linked Rows with Actions

When a row has both Link and Actions, Goshtoso keeps the row non-interactive and renders the Link in the first data cell. The primary navigation and trailing buttons remain separate keyboard controls.

Linked Rows with Actions Rendered example
CustomerIDNameEmailMembershipActions
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
Linked Rows with Actions
@table.Table(table.Config{
    Columns: columns,
    Rows: []table.Row{
        {
            ID:       "2335",
            Link:     "/customers/2335",
            LinkMode: table.LinkFull,
            Cells: map[string]table.Cell{
                "id":   {Text: "2335"},
                "name": {Text: "Alice Brown"},
            },
            Actions: customerActions("2335"),
        },
    },
})

Selectable Rows

Set ShowCheckbox: true to add row-selection controls with a header check-all toggle.

Selectable Rows Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]
2338Bob Johnson[email protected]
2342Sarah Adams[email protected]
Selectable Rows
@table.Table(table.Config{
    ShowCheckbox: true,
    Columns:      actionColumns(),
    Rows:         rows,
})

Users Table

Compose rich cells with table.ImageCell, badge.Badge, and button.Button.

Users Table Rendered example
UserIDMember SinceStatusAction
Alice Brown
Alice Brown [email protected]
2335Nov 14, 2021Active
Bob Johnson
Bob Johnson [email protected]
2338Aug 20, 2020Active
Ryan Thompson
Ryan Thompson [email protected]
2346Feb 5, 2022Canceled
Emily Rodriguez
Emily Rodriguez [email protected]
2349Jun 14, 2022Active
Alex Martinez
Alex Martinez [email protected]
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", "[email protected]")},
            "id":     {Text: "2335"},
            "since":  {Text: "Nov 14, 2021"},
            "status": {Component: badge.Badge(badge.Config{Label: "Active", Tone: badge.ToneSuccess, Size: badge.SizeSM})},
            "action": {Component: tableEditButton()},
        }},
    },
})

templ tableEditButton() {
    @button.Button(button.WithSize(button.SizeSmall)) {
        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.

Sortable Table (HTMX) Rendered example
CustomerID
Name
Email
Membership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
2345Alex Martinez[email protected]Gold
2346Ryan Thompson[email protected]Silver
2349Emily Rodriguez[email protected]Gold
Sortable Table (HTMX)
@table.Table(table.Config{
    ID:           "sortable-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows?variant=sortable&per_page=6"},
    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.

Lazy-Loaded Table Rendered example

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.

Paginated Table Rendered example
CustomerID
Name
Email
Membership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
Page 1 of 4
Paginated Table
@table.Table(table.Config{
    ID:           "paginated-table",
    HTMX: &table.HTMXConfig{Endpoint: "/api/components/table/rows"},
    Columns:      sortableColumns(),
    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.

Filtered Table Rendered example
CustomerID
Name
Email
Membership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
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 Appearance

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

Inline Filter Appearance Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
Page 1 of 4
Inline Filter Appearance
Filters: &table.FilterConfig{
    Appearance: table.FilterAppearanceInline,
    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.

Infinite Scroll Table Rendered example
CustomerIDNameEmailMembership
2335Alice Brown[email protected]Silver
2338Bob Johnson[email protected]Gold
2342Sarah Adams[email protected]Gold
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",
    },
})

Go API

v0.2.7

The examples above cover behavior and composition. pkg.go.dev is the canonical reference for exported types, functions, methods, and Go documentation.

github.com/araihu/goshtoso/components/table
Open v0.2.7 API