Skip to main content

Markdown Capabilities

Tabs

A CSS-only radio-group tabs container, authored as generic view/tabs directives — the first real, visible consumer of the tabs CSS/ARIA that already ships in packages/aup/src/primitives-css.ts.

Pipeline A does not support tabs. There's no view{mode="tabs"} directive concept in the marked-based pipeline. This container is pipeline-B only.

Tabs are authored as a generic view directive with mode="tabs", wrapping one view{label="..."} per panel — there is no dedicated tabs/tab directive name, unlike steps/step or the card family. The same colon-nesting rule applies: the outer view{mode="tabs"} needs more colons than the panels nested inside it.

Before this page, tabs had zero real usage in this repository (per #2453) — the CSS (.aup-tab-input/.aup-tab/.aup-tab-panel in packages/aup/src/primitives-css.ts) and the ARIA wiring (role="tablist"/aria-controls/aria-labelledby/aria-selected in renderer/primitives/view.ts's renderTabs()) existed but had never been rendered from real content. The examples below intentionally cover #2453's stated acceptance matrix: 2 tabs, 8+ tabs, long CJK labels, and a nested code block in a panel.

Two tabs

Source:

markdown
::::view{mode="tabs"}
:::view{label="pnpm"}
```bash
pnpm install
```
:::
:::view{label="npm"}
```bash
npm install
```
:::
::::

Rendered:

bash
pnpm install
bash
npm install

Under the hood, each panel is a CSS-only radio input + label pair (no JavaScript required to switch tabs); tabs-enhance.ts keeps aria-selected in sync as the user clicks, on top of an already fully keyboard-usable native radiogroup.

Eight-plus tabs

Source:

markdown
::::view{mode="tabs"}
:::view{label="Node.js"}
Runtime: Node.js 20+
:::
:::view{label="Bun"}
Runtime: Bun 1.x
:::
:::view{label="Deno"}
Runtime: Deno 2.x
:::
:::view{label="Python"}
Runtime: Python 3.12+
:::
:::view{label="Go"}
Runtime: Go 1.22+
:::
:::view{label="Rust"}
Runtime: Rust 1.75+
:::
:::view{label="Java"}
Runtime: Java 21+
:::
:::view{label="Ruby"}
Runtime: Ruby 3.3+
:::
::::

Rendered:

Runtime: Node.js 20+

Runtime: Bun 1.x

Runtime: Deno 2.x

Runtime: Python 3.12+

Runtime: Go 1.22+

Runtime: Rust 1.75+

Runtime: Java 21+

Runtime: Ruby 3.3+

The tab bar wraps rather than forcing the page into horizontal scroll at 8+ tabs, including at the 390px mobile breakpoint.

Long CJK labels

Source:

markdown
::::view{mode="tabs"}
:::view{label="安装与配置指南"}
第一步:安装依赖。
:::
:::view{label="部署到生产环境的完整流程"}
第二步:部署。
:::
::::

Rendered:

第一步:安装依赖。

第二步:部署。

CJK text has no natural word-break points the way space-separated Latin text does — a long CJK label must still fit the tab bar without pushing the page into horizontal scroll at 390px.

Nested code block in a panel

Source:

markdown
::::view{mode="tabs"}
:::view{label="Example"}
Full working example:

```typescript
export async function main() {
  const afs = await mountAfs();
  const items = await afs.list("/packages/content/docs/markdown");
  return items;
}
```
:::
:::view{label="Output"}
```json
{ "count": 7, "type": "docs" }
```
:::
::::

Rendered:

Full working example:

typescript
export async function main() {
  const afs = await mountAfs();
  const items = await afs.list("/packages/content/docs/markdown");
  return items;
}
json
{ "count": 7, "type": "docs" }

A fenced code block inside a tab panel renders exactly the same as anywhere else in this pipeline (language label, copy button) — the panel is just another block container.