Skip to content

Tabs

Organize content into switchable panels. Supports keyboard navigation, icons, badges, HTMX lazy-loaded panels, and URL-hash sync.

Default Rendered example
Groups tab is selected
Likes tab is selected
Comments tab is selected
Saved tab is selected
Usage Example
@tabs.Tabs(tabs.Config{
    ID: "demo",
    Tabs: []tabs.Tab{
        {ID: "groups", Label: "Groups", Content: groupsContent()},
        {ID: "likes", Label: "Likes", Content: likesContent()},
    },
})

With Icons

Give each Tab an Icon component to render before its label.

With Icons Rendered example
Groups tab is selected
Likes tab is selected
Comments tab is selected
Saved tab is selected
With Icons
@tabs.Tabs(tabs.Config{
    ID: "icon-demo",
    Tabs: []tabs.Tab{
        {ID: "groups", Label: "Groups", Icon: groupsIcon(), Content: groupsContent()},
        {ID: "likes", Label: "Likes", Icon: likesIcon(), Content: likesContent()},
    },
})

With Icons and Badges

Set Tab.Badge to show a count pill alongside the label.

With Icons and Badges Rendered example
Groups tab is selected
Likes tab is selected
Comments tab is selected
Saved tab is selected
With Icons and Badges
@tabs.Tabs(tabs.Config{
    ID: "badge-demo",
    Tabs: []tabs.Tab{
        {ID: "groups", Label: "Groups", Icon: groupsIcon(), Badge: "2", Content: groupsContent()},
        {ID: "likes", Label: "Likes", Icon: likesIcon(), Badge: "3124", Content: likesContent()},
    },
})

Custom Labels

Use LabelSlot for rich tab labels while Label remains the accessible name.

Custom Labels Rendered example
200 response is selected
404 response is selected
202 response is selected
Custom Labels
@tabs.Tabs(tabs.Config{
    ID: "status-demo",
    Tabs: []tabs.Tab{
        {ID: "ok", Label: "200", LabelSlot: statusBadge("200", badge.ToneSuccess), Content: responseContent("200")},
        {ID: "missing", Label: "404", LabelSlot: statusBadge("404", badge.ToneDanger), Content: responseContent("404")},
    },
})

HTMX Lazy Loading

Give a Tab an HTMX config instead of Content; its panel is fetched from the server the first time it's opened.

HTMX Lazy Loading Rendered example
Overview tab is selected
Loading...
Loading...
HTMX Lazy Loading
@tabs.Tabs(tabs.Config{
    ID: "htmx-demo",
    Tabs: []tabs.Tab{
        {ID: "overview", Label: "Overview", Content: overviewContent()},
        {ID: "details", Label: "Details", HTMX: &tabs.TabHTMX{Get: "/api/components/tab-content/details"}},
    },
})

URL Hash Sync

SyncHash: true mirrors the active tab in the URL fragment, so switching updates the hash and deep links like #comments restore on load.

URL Hash Sync Rendered example
Groups tab is selected
Likes tab is selected
Comments tab is selected
Saved tab is selected
URL Hash Sync
@tabs.Tabs(tabs.Config{
    ID:       "my-tabs",
    SyncHash: true,
    Tabs: []tabs.Tab{
        {ID: "groups", Label: "Groups", Content: groupsContent()},
        {ID: "comments", Label: "Comments", Content: commentsContent()},
    },
})

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/tabs
Open v0.2.7 API