---
title: "headings"
description: "Collects every heading of a document as `{ depth, slug, text }`, publishes the list as `data.headings`, and gives each heading an `id` matching its slug so an anchor link lands on it. A heading's text is the text it shows on the page, as `visibleText` reads it. On MDX the list is also appended to the tree as `export const headings`, so the compiled module carries its own table of contents."
url: "https://pitlane.tools/package/content/satteri/function/headings"
---

# headings

```ts
import { headings } from "@pitlane/content/satteri";
```

```ts
function headings(): MdastPluginEntry;
```

Collects every heading of a document as `{ depth, slug, text }`, publishes the list as `data.headings`, and gives each heading an `id` matching its slug so an anchor link lands on it. A heading's text is the text it shows on the page, as `visibleText` reads it. On MDX the list is also appended to the tree as `export const headings`, so the compiled module carries its own table of contents.

The plugin is a factory rather than a definition because Sätteri resolves a factory once per compile: a single `headings()` shared by a whole build gets fresh slug state per document, instead of the second document's `notes` reading `notes-1`.

The definition is written out rather than passed through Sätteri's `defineMdastPlugin`, whose entire body checks that `name` is set. Calling it would make this module import the `satteri` package, and `render.ts` imports this module: a Worker bundle whose collections `contentLayer()` already prebuilt would then have to resolve a native addon it can never load.

## Returns

`MdastPluginEntry`
