Tabs

把多个视图装进同一块空间——读者点 tab 切换显示什么,节省垂直空间。 适合"同一信息的多种表达"(多语言代码 / raw 数据 vs chart / 桌面 vs 移动端 vs API)。


When to use

  • ✅ 多语言代码示例(同一段逻辑用 JS / Python / Rust 三种实现)
  • ✅ 同一数据的多种视图(原始 JSON / 表格 / 图表)
  • ✅ 多平台/环境对比(macOS / Windows / Linux 安装步骤;iOS / Android 截图)
  • ✅ API 的请求 / 响应 对比(curl / Node.js / Python 调用方式)
  • ❌ 平级独立内容(不需要切换,全部并列展示)→ 用 Layout grid
  • ❌ 严格序列(step 1 → 2 → 3)→ 用 Stepper
  • ❌ 强对比(用户必须看见所有项才能决策)→ 用 Layout,tabs 会让其他选项"看不见"

Basic syntax

\```tabs
:::tab title=JavaScript
\```js
console.log('hello');
\```
:::

:::tab title=Python
\```py
print('hello')
\```
:::

:::tab title=Rust
\```rust
println!("hello");
\```
:::
\```

渲染:顶部一排 tab bar,第一个 tab 默认激活;点击其他 tab 切换内容区。tab 之间共用同一垂直空间。


All options

Block-level: ```tabs

Option Type Default Purpose
default int / string 0(第一个) 默认激活 tab 的 index 或 title
position enum top tab bar 位置(top / bottom)

Tab-level: :::tab

Option Type Default Purpose
title string (必填) tab bar 上显示的文字。建议短(< 20 字符)
disabled bool false 灰显且不可点击(用于占位 / 预告)

title 含空格请加引号:title="My Tab"。


Examples

Example 1:多语言代码

\```tabs
:::tab title=JavaScript
\```js
async function getUser(id) {
  const r = await fetch(`/api/user/${id}`);
  return r.json();
}
\```
:::

:::tab title=Python
\```py
import requests
def get_user(id):
    return requests.get(f'/api/user/{id}').json()
\```
:::

:::tab title=Go
\```go
func GetUser(id string) (*User, error) {
    resp, err := http.Get("/api/user/" + id)
    // ...
}
\```
:::
\```

渲染:3 个 tab "JavaScript / Python / Go",点击切换不同语言代码。读者看自己熟悉的那一种就好。

Example 2:富内容(含 callout / 列表)

\```tabs
:::tab title=macOS
1. 下载 `.dmg`
2. 拖到 Applications
3. 启动

> [!INFO]
> Apple Silicon 和 Intel universal 二进制
:::

:::tab title=Windows
1. 下载 `.msi`
2. 双击安装
3. 从开始菜单启动

> [!WARN]
> 需要 Windows 10+
:::

:::tab title=Linux
\```bash
sudo apt install rho   # Debian/Ubuntu
sudo dnf install rho   # Fedora
\```

或下载 `.AppImage` 直接运行。
:::
\```

渲染:3 平台并列在 tabs 里。Tab 内容可含任意 markdown(列表、代码块、callout、链接),不只是纯文字。

Example 3:同一数据的 3 种视图

\```tabs
:::tab title=Raw
\```json
{"q1": 100, "q2": 130, "q3": 95, "q4": 180}
\```
:::

:::tab title=Table
| Quarter | Revenue |
|---|---|
| Q1 | 100 |
| Q2 | 130 |
| Q3 | 95 |
| Q4 | 180 |
:::

:::tab title=Chart
\```vega-lite
{
  "data": {"values": [{"q":"Q1","v":100},{"q":"Q2","v":130},{"q":"Q3","v":95},{"q":"Q4","v":180}]},
  "mark": "bar",
  "encoding": {"x": {"field": "q"}, "y": {"field": "v", "type": "quantitative"}}
}
\```
:::
\```

渲染:同一组季度营收数据,三种视图(JSON / 表格 / 柱状图)。读者按需切换;表格适合精确读、图表适合趋势看、JSON 适合复制走。

Example 4:指定默认激活 + disabled

\```tabs default="Production"
:::tab title=Development
开发环境配置...
:::

:::tab title=Staging
预发环境配置...
:::

:::tab title=Production
**生产环境配置**(默认显示,因为最关键)
:::

:::tab title=Edge disabled=true
Edge 网关配置 — 🚧 v0.7 推出
:::
\```

渲染:默认显示 "Production" tab(因为 default="Production"),不是第一个。"Edge" tab 灰显且不可点击。


Plain-text fallback behavior

:::tab 是 markdown directive 容器。在不支持 directive 的 reader 里:

:::tab title=JavaScript
content
:::

→ :::tab title=... 和 ::: 显示为字面量;tab 内的 markdown(代码块、列表、链接)正常渲染。所有 tab 内容展开为一连串显示——读者能看到所有信息,只是失去 "选一个看" 的交互。

具体各 reader:

Reader 渲染效果
Rho 完整 tabs(顶部 bar + 切换)
GitHub web :::tab title=... 字面量 + tab 内容并列展开
Obsidian 同上(除非装了 directive 插件)
VS Code 默认预览 同上
cat / less plain text

所有 tab 内容都可读——这是 plain-text fallback 的核心。读者最坏看到的是"全部 tab 内容堆在一起",不是错误。


Common pitfalls

1. 忘记 title

\```tabs
:::tab                ← ❌ 缺 title
内容
:::
\```

→ tab bar 显示空白或 "Tab 1"。title 是必填。

2. title 含空格忘记引号

:::tab title=My Tab     ← ❌ "Tab" 被当成下个 modifier
:::tab title="My Tab"   ← ✅

3. tab 数过多 (>5)

tab 数 体验
1-3 最佳
4-5 OK
6-8 tab bar 拥挤;移动端会折行或滚动
> 8 反模式,改用 Layout grid + cards 全部展开或 sidebar nav

4. tab 内容深度极不均衡

\```tabs
:::tab title=A
A 方案非常长描述:5 段、3 列表、嵌套 callout、代码块……
:::
:::tab title=B
B 方案一句话。
:::
\```

→ 切到 B 时空荡,切到 A 时撑满。视觉跳变过大。 改进:补 B 内容到对等深度;或改用 Layout grid 同时展示让读者横向比较。

5. 缺 ::: 关闭

\```tabs
:::tab title=A
A 内容
                ← ❌ 缺 :::
:::tab title=B
B 内容
:::
\```

→ 整个 tabs 块解析失败。每个 :::tab 必须配对 ::: 关闭。

6. 嵌套 tabs(不推荐)

\```tabs
:::tab title=Outer
\```tabs       ← ⚠️ tabs 套 tabs,UI 极易混乱
:::tab title=Inner
:::
\```
:::
\```

→ 技术上 Nested DSL 支持,但视觉上读者很难分清外层和内层 tabs 边界。 改进:把内层 tabs 提到外面平级,或改用 stepper(外层 step 内放 tabs)。

7. tabs 里嵌 interact 块——可以,但注意状态

:::tab title=Demo
\```interact
slider x 0 10 5 1
template stl:
[选中] -> [{x}]
\```
:::

✅ 合法。但切到其他 tab 再切回来时,slider 的状态可能 reset 到初始值(看 reader 实现)。重要的 demo 别藏在非默认 tab。


Tabs vs Stepper vs Layout — 选择依据

场景 用
多视图 / 多语言 / 多版本(读者选一个看) Tabs
严格步骤序列(一步步走,含 Prev/Next) Stepper
平级对比(读者必须看到全部一起) Layout grid
时间事件(带日期) Timeline

See also