---
title: Remark plugins
description: The default plugin stack that flattens MDX components into markdown.
group: reference
lastModified: '2026-05-11T20:02:32-07:00'
lastAuthor: 'github-actions[bot]'
---
# Remark plugins

The remark stack is what turns interactive MDX into agent-readable markdown. Imports get stripped first, placeholders get resolved, then each named component is flattened into a markdown equivalent. Order matters.

```ts
import {
  defaultRemarkPlugins,
  remarkInclude,
  remarkTypeTableToMarkdown,
} from "leadtype/remark";
```

## The default stack

```mermaid
`flowchart TB
src["MDX (mdast)"]
ri["remarkRemoveImports"]
rj["remarkRemoveJsxComments"]
rd["remarkResolveDocPlaceholders"]
rau["remarkAudienceToMarkdown"]
rs["remarkSectionToMarkdown"]
rc["remarkCalloutToMarkdown"]
rcd["remarkCardsToMarkdown"]
rdt["remarkDetailsToMarkdown"]
rm["remarkMermaidToMarkdown"]
rct["remarkCommandTabsToMarkdown"]
rst["remarkStepsToMarkdown"]
rt["remarkTabsToMarkdown"]
rtt["remarkTypeTableToMarkdown"]
ra["remarkAccordionToMarkdown"]
rts["remarkTopicSwitcherToMarkdown"]
rft["remarkFileTreeToMarkdown"]
rp["remarkPromptToMarkdown"]
re["remarkExampleToMarkdown"]
out["clean markdown"]
src --> ri --> rj --> rd --> rau --> rs --> rc --> rcd --> rdt --> rm --> rct --> rst --> rt --> rtt --> ra --> rts --> rft --> rp --> re --> out`
```

`defaultRemarkPlugins` runs the stack in this order:

1. `remarkRemoveImports` — strip MDX `import` and `export` statements.
2. `remarkRemoveJsxComments` — strip `{/* ... */}` JSX comments.
3. `remarkResolveDocPlaceholders` — replace `{framework}` and similar placeholders in URLs.
4. `remarkAudienceToMarkdown` — include `<Audience target="agent">` and remove `<Audience target="human">`.
5. `remarkSectionToMarkdown` — flatten `<Section>` containers.
6. `remarkCalloutToMarkdown` — `<Callout>` → blockquote.
7. `remarkCardsToMarkdown` — `<Cards>` → bulleted link list.
8. `remarkDetailsToMarkdown` — flatten `<Details>` blocks.
9. `remarkMermaidToMarkdown` — `<Mermaid>` → fenced ` ```mermaid ` block.
10. `remarkCommandTabsToMarkdown` — `<CommandTabs>` → markdown table.
11. `remarkStepsToMarkdown` — `<Steps>` → ordered list.
12. `remarkTabsToMarkdown` — `<Tabs>` → bold heading per tab.
13. `remarkTypeTableToMarkdown` — `<TypeTable>` and `<ExtractedTypeTable>` → markdown table.
14. `remarkAccordionToMarkdown` — `<Accordion>` → flattened sections (open/closed state ignored).
15. `remarkTopicSwitcherToMarkdown` — `<TopicSwitcher>` → labeled link list.
16. `remarkFileTreeToMarkdown` — `<FileTree>` → fenced text tree.
17. `remarkPromptToMarkdown` — `<Prompt>` → fenced ` ```prompt ` block.
18. `remarkExampleToMarkdown` — `<Example>` → fenced code block plus body.

## Why order matters

Imports must go before placeholder resolution, because some placeholders read from imported modules. Placeholder resolution must go before component flatteners, because flatteners assume URLs are final strings, not template literals. The component flatteners run last so each one sees a clean tree.

Don't reorder casually. If you need a custom plugin to run before a flattener (for example, to transform a custom component into one of the contracted names), insert it after `remarkResolveDocPlaceholders` and before the flattener you want to feed.

## Optional plugins

### remarkInclude

Add this when the source docs use include tags or partial composition:

```ts
import { defaultRemarkPlugins, remarkInclude } from "leadtype/remark";

remarkPlugins: [remarkInclude, ...defaultRemarkPlugins];
```

Place it before the default stack so included content expands before any flattener sees it.

Use `src` or text content to point at a shared markdown, MDX, or code file:

```mdx
<include src="./shared/auth.mdx" />

<include>./shared/auth.mdx</include>

<import src="./shared/auth.mdx" />

<include-c15t src="./shared/auth.mdx" />
```

Markdown and MDX files are parsed and spliced into the current page. Frontmatter from the included file is stripped. Non-markdown files are included as fenced code; pass `lang` when the extension is not enough:

```mdx
<include src="../examples/login.ts" />

<include src="../examples/env" lang="bash" />
```

To reuse one section from a larger partial, append `#section-id` and wrap the reusable block in a lowercase HTML `section` element:

```mdx
<include src="./shared/auth.mdx#session-flow" />
```

```mdx
<section id="session-flow">
  This content can be reused in multiple pages.
</section>
```

Section extraction currently matches lowercase `<section id="...">` only. A capitalized MDX component such as `<Section id="session-flow">` is flattened later by `remarkSectionToMarkdown`, but it is not an include anchor.

Relative paths resolve from the including file first. You can also pass base paths to the plugin for shared partial roots:

```ts
remarkPlugins: [
  [remarkInclude, ["docs", "content"]],
  ...defaultRemarkPlugins,
];
```

Nested includes are supported. The plugin keeps the included file's directory as `baseDir` for nested relative paths, so a partial can include files next to itself.

`leadtype generate` and `leadtype lint` run `remarkInclude` automatically. Custom conversion scripts must add it explicitly.

### remarkTypeTableToMarkdown (with basePath)

`<ExtractedTypeTable>` reads a TypeScript file at conversion time. When the file path is relative, the plugin needs a `basePath` to resolve from. Override the default plugin entry to pass options:

```ts
import {
  defaultRemarkPlugins,
  remarkTypeTableToMarkdown,
} from "leadtype/remark";

const remarkPlugins = [
  ...defaultRemarkPlugins.filter((p) => p !== remarkTypeTableToMarkdown),
  [remarkTypeTableToMarkdown, { basePath: process.cwd() }],
];
```

In your MDX, point at a local TypeScript file by `path` and the type by `name`:

```mdx
<ExtractedTypeTable
  name="PipelineExampleOptions"
  path="./src/types.ts"
/>
```

At conversion time, the plugin reads the file, finds the named type, and emits a markdown table with one row per property. The rendered output is what ships in the converted `.md` and root `llms-full.txt` — no JSX, no client-side rendering needed.

## Plugin selection rules

* Use `defaultRemarkPlugins` for any agent-facing or LLM output.
* Add `remarkInclude` when docs are composed from shared fragments.
* Use individual plugins only when you intentionally want to omit a flattener (e.g. you don't use `<TypeTable>` and want to skip its processing cost).
* If output looks wrong, read the converted `.md` first. The fix is almost never reordering — it's usually a custom plugin between two existing ones.
