`codeTabs` 機能は、関連するコードブロックをインタラクティブなタブストリップにまとめます。連続するフェンスブロックを `:::code-group` ディレクティブでラップすると、zfb がフレームワーク側でタブとして描画する `<CodeGroup>` 要素を出力します。

:::note[標準プリセットに含まれます]

`zudoDoc()` は Code Tabs を有効にします。個別の設定フィールドは不要です。

:::

## 設定

```ts title="zfb.config.ts"
import { defineConfig } from "zfb/config";
import { zudoDoc } from "@takazudo/zudo-doc/config";

export default defineConfig(
  zudoDoc({
    siteName: "My Docs",
  }),
);
```

## 記述構文

2 つ以上のフェンスコードブロックを `:::code-group` ディレクティブでラップします。各ブロックのタブラベルは、その `title="…"` 属性から導出されます。

````md
:::code-group

```ts title="index.ts"
export const greeting: string = "hello";
```

```js title="index.js"
export const greeting = "hello";
```

:::
````

:::warning[The `:::code-group` directive is the trigger — not bare consecutive fences]

Two adjacent fenced code blocks on their own do **not** become tabs; they render as two independent code blocks. The tab grouping is triggered only by the explicit `:::code-group` directive wrapping the fences.

:::

## Tab label resolution

Each tab's label follows this priority order:

1. The `title="…"` attribute on the fence
2. The language id (e.g. `ts`, `js`)
3. The fallback string `"tab"` when neither is present

## Live demo

The directive above renders as:

:::code-group

```ts title="index.ts"
export const greeting: string = "hello";
```

```js title="index.js"
export const greeting = "hello";
```

:::

## 出力

`:::code-group` ディレクティブは、解決されたラベル配列を保持する `tabs` プロパティと、フェンスごとに 1 つの `<pre data-lang="…">` 子要素を持つ `<CodeGroup>` JSX 要素を生成します。

```jsx
<CodeGroup tabs={["index.ts", "index.js"]}>
  <pre data-lang="ts">export const greeting: string = "hello";</pre>
  <pre data-lang="js">export const greeting = "hello";</pre>
</CodeGroup>
```

zudo-doc はパッケージ所有の `<CodeGroup>` 実装をデフォルトで登録し、`tabs` 配列と `<pre data-lang>` の子要素を既存の `<Tabs>` / `<TabItem>` UI にマッピングします。[`mdxExtras`](https://zudo-doc.takazudomodular.com/ja/docs/guides/custom-components#%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E7%99%BB%E9%8C%B2-mdxextras) を通じて上書きできます。各 `<pre>` 内のコードは生のテキストです（Rust パイプラインは `:::code-group` フェンス内でシンタックスハイライトを実行しません）。

## `name` によるタブの同期

オプションの `name` 属性を使うと、同じページ内で同じ名前を持つすべての `:::code-group` ブロックが連動します。一方のグループでタブをクリックすると、同じ名前を持つほかのグループも — 対応するラベルのタブが存在する場合に — 自動的に切り替わります。

````md
:::code-group{name="package-manager"}

```sh title="npm"
npm install my-lib
```

```sh title="pnpm"
pnpm add my-lib
```

:::

:::code-group{name="package-manager"}

```sh title="npm"
npm run dev
```

```sh title="pnpm"
pnpm dev
```

:::
````

選択したタブは `localStorage` の `tabs-group-{name}` というキーにも保存されます。次回のページ読み込み時、同じ名前を持つすべてのグループが保存済みのタブを復元します（保存されたラベルがグループに存在しない場合はデフォルトのタブにフォールバックします）。

内部的には、`name` は zfb によって `<CodeGroup>` コンポーネントへの prop として転送され、`<CodeGroup>` はそれを下層の `<Tabs>` コンポーネントの `groupId` として渡します。`TabsInit` スクリプトはレンダリングされた DOM の `data-group-id` を読み取り、クリック時に同じ `groupId` を持つすべてのコンテナを同期しながら、`localStorage` への読み書きによってページをまたいだ永続化を行います。

## 補足

- 空の `:::code-group` コンテナ（フェンスなし）は、プレーンテキストのまま変更されません。
- ネストした `:::code-group` ディレクティブはサポートされていません。