The `tocExport` feature walks a document's headings and injects an MDX named export — `export const toc` — at the top of each processed file, giving sidebar and floating-TOC components a structured table-of-contents.

:::note[Requires zfb 0.1.0-next.14 or newer]

Enabling `tocExport` **broke the build** at zfb `0.1.0-next.13`: the injected `export const toc = [...]` line was emitted at an indented column, so MDX parsed it as content rather than an ESM export, producing ~153 esbuild `Expected "}"` errors across the corpus ([#1814](https://github.com/zudolab/zudo-doc/issues/1814)). It is fixed in zfb `0.1.0-next.14` (upstream Takazudo/zudo-front-builder#599 — the export is now hoisted to column 0) and is enabled in zudo-doc's `zfb.config.ts`. Every page in this corpus, including this one, now carries a real `export const toc`.

:::

## Configuration

`zudoDoc()` includes `tocExport: {}` in the standard preset — no separate configuration field is necessary for the default `maxDepth: 3`. (It is an object-typed feature — the `true` shorthand is rejected — so the preset always passes `{}`, never `true`.)

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

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

To limit the heading depth, spread the preset's `markdown.features` and override `tocExport` — a bare `defineConfig({ markdown: { features } })` would discard the rest of the preset:

```ts title="zfb.config.ts"
const base = zudoDoc({
  // ...your project settings
});

export default defineConfig({
  ...base,
  markdown: {
    ...base.markdown,
    features: {
      ...base.markdown.features,
      tocExport: { maxDepth: 2 },
    },
  },
});
```

## Options

| Option | Default | Description |
| --- | --- | --- |
| `maxDepth` | `3` | Maximum heading depth (absolute, 2–6). `2` = h2 only; `3` = h2 + h3. |

## Exported shape

The feature injects an `export const toc` whose entries follow this type:

```ts
type TocEntry = {
  depth: number; // absolute heading depth: 2 | 3 | 4 | 5 | 6
  id: string; // slug assigned by the heading-links pass
  text: string; // plain-text heading content (hash-link stripped)
  children: TocEntry[]; // nested sub-headings within maxDepth
};
```

## Example output

For a document with h2 and h3 headings, the injected export looks like:

```ts
export const toc = [
  {
    depth: 2,
    id: "introduction",
    text: "Introduction",
    children: [{ depth: 3, id: "introduction-background", text: "Background", children: [] }],
  },
  { depth: 2, id: "conclusion", text: "Conclusion", children: [] },
];
```

The nested `id: "introduction-background"` reflects zudo-doc's [hierarchical heading IDs](https://zudo-doc.takazudomodular.com/docs/markdown-features/heading-links#hierarchical-ids): the h3 `id` is prefixed with its h2 ancestor.

## Notes

- The export runs after the heading-links pass, so the `id` slugs are final, deduplicated, and follow the [hierarchical ID contract](https://zudo-doc.takazudomodular.com/docs/markdown-features/heading-links#hierarchical-ids).
- `tocExport` works independently of [Heading Marker TOC](https://zudo-doc.takazudomodular.com/docs/markdown-features/heading-marker-toc) — enabling one does not interfere with the other.
- zudo-doc's existing TOC island is not driven by this export; the two are separate mechanisms.