Rewrote all the docs - more noob friendly now.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-05 23:55:26 +05:00
parent c1e1f74557
commit b530bb8c97
35 changed files with 2159 additions and 2341 deletions
+62 -63
View File
@@ -1,50 +1,27 @@
# Tabs
A tabbed interface. One tab panel is visible at a time. The active tab has a highlighted style; all others are hidden. Client-side JS switches panels without a server round-trip.
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.
---
## HTML structure
## Quick example
```
div[id].tabs-root
div.tabs-list.flex.gap-1.border-b.mb-4 ← tab button strip
button.tabs-trigger[data-tab={tabId}] ← one per tab; ACTIVE/INACTIVE variant
{label}
div.tabs-panel[data-tab={tabId}] ← one per tab; hidden or visible
{content}
```csharp
new Tabs(
id: "settings-tabs",
tabs: new[]
{
("general", "General", "<p>General settings here.</p>"),
("security", "Security", "<p>Password and 2FA here.</p>"),
("billing", "Billing", "<p>Payment details here.</p>"),
})
```
---
## CSS mechanics
| Class | Effect |
|---|---|
| `tabs-trigger` | `px-4 py-2 text-sm font-medium rounded-t-md -mb-px` |
| Active trigger | `bg-background border border-b-0 border-border text-foreground` |
| Inactive trigger | `text-muted-foreground hover:text-foreground hover:bg-muted/40` |
| `tabs-panel[hidden]` | `display: none` via the HTML `hidden` attribute |
The first tab is active by default.
---
## JavaScript (`initTabs` in `components.js`)
Runs on `DOMContentLoaded` and `htmx:afterSwap`.
**Per-instance initialization:**
1. Guard `_tabsInit` prevents double-binding
2. Reads all `.tabs-trigger` and `.tabs-panel` elements within the root
3. Activates the first tab on init (removes `hidden`, applies active class)
4. On trigger click:
- Deactivate all panels (set `hidden`, downgrade trigger class to inactive)
- Activate the clicked panel by matching `data-tab` attribute
- Apply active class to the clicked trigger
---
## Constructor signature
## All the options
```csharp
public Tabs(
@@ -52,52 +29,74 @@ public Tabs(
IEnumerable<(string Id, string Label, string Content)> tabs)
```
| Parameter | Description |
| Parameter | What it does |
|---|---|
| `id` | Root element id — must be unique per page if multiple Tabs are rendered |
| `tabs` | List of `(Id, Label, Content)` tuples; `Id` must be unique within this instance |
| `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. |
---
## Usage examples
## Real-world examples
### Simple tabbed content
### User profile page with tabbed sections
```csharp
new Tabs(
id: "settings-tabs",
id: "profile-tabs",
tabs: new[]
{
("general", "General", "<p>General settings content here.</p>"),
("security", "Security", "<p>Security settings content here.</p>"),
("billing", "Billing", "<p>Billing details here.</p>"),
("overview", "Overview", $"<p>Joined {user.CreatedAt:MMMM yyyy}</p>"),
("activity", "Activity", activityHtml),
("settings", "Settings", settingsFormHtml),
})
```
### HTML-rich content in a tab
### Tab containing a full component
Pre-render inner components to HTML strings before embedding them:
```csharp
new Tabs(
id: "code-tabs",
tabs: new[]
{
("csharp", "C#", "<pre><code>var x = 42;</code></pre>"),
("fsharp", "F#", "<pre><code>let x = 42</code></pre>"),
("vb", "VB.NET", "<pre><code>Dim x As Integer = 42</code></pre>"),
})
```
### Embedding a full component in a tab
```csharp
// Pre-render the inner component to HTML string
var buf = new System.Buffers.ArrayBufferWriter<byte>();
new Table(headers: cols, rows: data).Render(new HtmxRenderContext(buf));
var tableHtml = System.Text.Encoding.UTF8.GetString(buf.WrittenSpan);
string Render(IHtmxComponent c)
{
var buf = new System.Buffers.ArrayBufferWriter<byte>();
c.Render(new HtmxRenderContext(buf));
return System.Text.Encoding.UTF8.GetString(buf.WrittenSpan);
}
new Tabs(
id: "report",
tabs: new[]
{
("table", "Table", Render(new Table(headers: cols, rows: rows))),
("summary", "Summary", summaryHtml),
})
```
### Code samples in multiple languages
```csharp
new Tabs(
id: "code-example",
tabs: new[]
{
("csharp", "C#", "<pre><code>var x = 42;</code></pre>"),
("fsharp", "F#", "<pre><code>let x = 42</code></pre>"),
})
```
---
## 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", "<p>High level numbers.</p>"),
("detail", "Detail", tableHtml),