# Tabs A row of clickable tabs that each reveal different content. Only one tab is visible at a time. Think of it like a filing cabinet with labelled dividers — you flip between sections without leaving the page. --- ## Quick example ```csharp new Tabs( id: "settings-tabs", tabs: new[] { ("general", "General", "
General settings here.
"), ("security", "Security", "Password and 2FA here.
"), ("billing", "Billing", "Payment details here.
"), }) ``` The first tab is active by default. --- ## All the options ```csharp public Tabs( string id, IEnumerable<(string Id, string Label, string Content)> tabs) ``` | Parameter | What it does | |---|---| | `id` | A unique identifier for this tabs widget. Required if you have more than one `Tabs` on the same page. | | `tabs` | The list of tabs. Each is a `(Id, Label, Content)` tuple. | **Tab tuple fields:** | Field | What it does | |---|---| | `Id` | A unique identifier for this tab within the widget. Used internally to link the trigger to the panel. | | `Label` | The text shown on the tab button. | | `Content` | The HTML content shown when this tab is active. | --- ## Real-world examples ### User profile page with tabbed sections ```csharp new Tabs( id: "profile-tabs", tabs: new[] { ("overview", "Overview", $"Joined {user.CreatedAt:MMMM yyyy}
"), ("activity", "Activity", activityHtml), ("settings", "Settings", settingsFormHtml), }) ``` ### Tab containing a full component Pre-render inner components to HTML strings before embedding them: ```csharp string Render(IHtmxComponent c) { var buf = new System.Buffers.ArrayBufferWritervar x = 42;"),
("fsharp", "F#", "let x = 42"),
})
```
---
## How it works
All tab panels are present in the HTML on page load. JavaScript in `components.js` hides all but the first using the HTML `hidden` attribute. When a tab button is clicked, its matching panel has `hidden` removed and all others get it added back. No server request is made — this is pure client-side switching.
{
("summary", "Summary", "High level numbers.
"), ("detail", "Detail", tableHtml), }) ``` ### Multiple independent tab groups ```csharp new Tabs(id: "tabs-a", tabs: setA) new Tabs(id: "tabs-b", tabs: setB) ``` The `id` scopes JS initialization — each Tabs instance is independent. --- ## Tips and tricks - The `Id` of each tab tuple is used as the `data-tab` attribute — keep it URL-safe and unique within the instance. - The first tab is always activated on page load regardless of which tab was active before navigation. - Tab `Content` is raw HTML — HTML-encode any user-supplied values. - For lazy-loaded tab content, place HTMX attributes in the `Content` string and use `hx-trigger="revealed"` to load content when the panel becomes visible. - Tabs do not push to the URL hash by default. If you need deep-linkable tabs, listen to the `click` event on `.tabs-trigger` elements and update `location.hash`. - Tabs do not push to the URL hash by default. If you need deep-linkable tabs, listen to the `click` event on `.tabs-trigger` elements and update `location.hash`. --- ## Complete page example **`Templates/ProfileSettingsPage.htmx`** ```html