> ## Documentation Index
> Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Markdown

> 使用 Bun 内置的 Markdown API 解析并渲染 Markdown，支持 GFM 扩展和自定义渲染回调

<Callout type="note">**不稳定的 API** — 该 API 正在积极开发中，未来版本的 Bun 可能会发生变化。</Callout>

Bun 包含一个用 Zig 编写的快速内置 Markdown 解析器。它支持 GitHub 风格的 Markdown (GFM) 扩展，并提供三种 API：

* `Bun.markdown.html()` — 将 Markdown 渲染为 HTML 字符串
* `Bun.markdown.render()` — 使用自定义回调渲染 Markdown 的每个元素
* `Bun.markdown.react()` — 渲染 Markdown 为 React JSX 元素

***

## `Bun.markdown.html()`

将 Markdown 字符串转换为 HTML。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const html = Bun.markdown.html("# Hello **world**");
// "<h1>Hello <strong>world</strong></h1>\n"
```

默认启用 GFM 扩展，如表格、删除线和任务列表：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const html = Bun.markdown.html(`
| Feature      | Status |
|-------------|--------|
| Tables       | ~~done~~ |
| Strikethrough| ~~done~~ |
| Task lists   | done |
`);
```

### 选项

作为第二个参数传入选项对象以配置解析器：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const html = Bun.markdown.html("some markdown", {
  tables: true, // GFM 表格（默认：true）
  strikethrough: true, // GFM 删除线（默认：true）
  tasklists: true, // GFM 任务列表（默认：true）
  tagFilter: true, // 过滤不允许的 HTML 标签
  autolinks: true, // 自动链接 URL、邮箱和 www. 开头的链接
});
```

所有可用选项：

| 选项                     | 默认值     | 描述                                       |
| ---------------------- | ------- | ---------------------------------------- |
| `tables`               | `false` | GFM 表格                                   |
| `strikethrough`        | `false` | GFM 删除线 (`~~text~~`)                     |
| `tasklists`            | `false` | GFM 任务列表 (`- [x] item`)                  |
| `autolinks`            | `false` | 启用自动链接 — 参见 [自动链接](#autolinks)           |
| `headings`             | `false` | 启用标题 ID 和自动链接 — 参见 [标题 ID](#heading-ids) |
| `hardSoftBreaks`       | `false` | 把软换行视为硬换行                                |
| `wikiLinks`            | `false` | 启用 `[[wiki links]]`                      |
| `underline`            | `false` | `__text__` 渲染为 `<u>` 而非 `<strong>`       |
| `latexMath`            | `false` | 启用 `$inline$` 和 `$$display$$` 数学模式       |
| `collapseWhitespace`   | `false` | 折叠文本中的空白                                 |
| `permissiveAtxHeaders` | `false` | 允许 ATX 标题在 `#` 之后无空格                     |
| `noIndentedCodeBlocks` | `false` | 禁用缩进代码块                                  |
| `noHtmlBlocks`         | `false` | 禁用 HTML 块                                |
| `noHtmlSpans`          | `false` | 禁用内联 HTML                                |
| `tagFilter`            | `false` | 过滤不允许的 HTML 标签                           |

#### 自动链接

传入 `true` 可启用所有自动链接类型，或者传入对象以精细控制：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 启用所有自动链接（URL、WWW、邮箱）
Bun.markdown.html("Visit www.example.com", { autolinks: true });

// 仅启用特定类型
Bun.markdown.html("Visit www.example.com", {
  autolinks: { url: true, www: true },
});
```

#### 标题 ID

传入 `true` 可同时启用标题 ID 和自动链接标题，或者传入对象进行细粒度控制：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 启用标题 ID 和自动链接标题
Bun.markdown.html("## Hello World", { headings: true });
// '<h2 id="hello-world"><a href="#hello-world">Hello World</a></h2>\n'

// 仅启用标题 ID（无自动链接）
Bun.markdown.html("## Hello World", { headings: { ids: true } });
// '<h2 id="hello-world">Hello World</h2>\n'
```

***

## `Bun.markdown.render()`

解析 Markdown 并使用自定义 JavaScript 回调渲染。这样可以完全控制输出格式——你可以生成带自定义类的 HTML、React 元素、ANSI 终端输出或任何其他字符串格式。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = Bun.markdown.render("# Hello **world**", {
  heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
  strong: children => `<b>${children}</b>`,
  paragraph: children => `<p>${children}</p>`,
});
// '<h1 class="title">Hello <b>world</b></h1>'
```

### 回调函数签名

每个回调接收：

1. **`children`** — 元素累积的内容字符串
2. **`meta`**（可选）— 带有元素特定元数据的对象

返回一个字符串替代元素渲染。返回 `null` 或 `undefined` 则完全忽略该元素。如果未注册元素回调，则其子元素会原样通过。

### 块级回调

| 回调           | 元数据                                         | 描述                                              |
| ------------ | ------------------------------------------- | ----------------------------------------------- |
| `heading`    | `{ level: number, id?: string }`            | 标题级别 1–6。启用 `headings: { ids: true }` 时会设置 `id` |
| `paragraph`  | —                                           | 段落块                                             |
| `blockquote` | —                                           | 引用块                                             |
| `code`       | `{ language?: string }`                     | 围栏代码或缩进代码块。`language` 是围栏信息字符串（若指定）             |
| `list`       | `{ ordered: boolean, start?: number }`      | 有序或无序列表。有序列表的起始数字为 `start`                      |
| `listItem`   | `{ checked?: boolean }`                     | 列表项。任务列表项（`- [x]` / `- [ ]`）会设置 `checked`       |
| `hr`         | —                                           | 分割线                                             |
| `table`      | —                                           | 表格块                                             |
| `thead`      | —                                           | 表头                                              |
| `tbody`      | —                                           | 表格主体                                            |
| `tr`         | —                                           | 表格行                                             |
| `th`         | `{ align?: "left" \| "center" \| "right" }` | 表头单元格。指定对齐时设置 `align`                           |
| `td`         | `{ align?: "left" \| "center" \| "right" }` | 表格单元格。指定对齐时设置 `align`                           |
| `html`       | —                                           | 原始 HTML 内容                                      |

#### 列表项元数据

`listItem` 回调会接收渲染标记所需的所有信息：

* `index` — 在父列表中的基于 0 的位置
* `depth` — 父列表的嵌套层级（0 = 顶层）
* `ordered` — 父列表是否为有序列表
* `start` — 父列表的起始编号（仅当 `ordered` 为 true 时）
* `checked` — 任务列表状态（仅用于 `- [x]` / `- [ ]` 项）

### 行内回调

| 回调              | 元数据                                | 描述                  |
| --------------- | ---------------------------------- | ------------------- |
| `strong`        | —                                  | 加粗强调 (`**text**`)   |
| `emphasis`      | —                                  | 斜体强调 (`*text*`)     |
| `link`          | `{ href: string, title?: string }` | 链接                  |
| `image`         | `{ src: string, title?: string }`  | 图像                  |
| `codespan`      | —                                  | 行内代码 (`` `code` ``) |
| `strikethrough` | —                                  | 删除线 (`~~text~~`)    |
| `text`          | —                                  | 纯文本内容               |

### 示例

#### 带类的自定义 HTML

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const html = Bun.markdown.render("# Title\n\nHello **world**", {
  heading: (children, { level }) => `<h${level} class="heading heading-${level}">${children}</h${level}>`,
  paragraph: children => `<p class="body">${children}</p>`,
  strong: children => `<strong class="bold">${children}</strong>`,
});
```

#### 去除所有格式

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const plaintext = Bun.markdown.render("# Hello **world**", {
  heading: children => children,
  paragraph: children => children,
  strong: children => children,
  emphasis: children => children,
  link: children => children,
  image: () => "",
  code: children => children,
  codespan: children => children,
});
// "Hello world"
```

#### 忽略元素

返回 `null` 或 `undefined` 可从输出中删除某元素：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = Bun.markdown.render("# Title\n\n![logo](img.png)\n\nHello", {
  image: () => null, // 移除所有图片
  heading: children => children,
  paragraph: children => children + "\n",
});
// "Title\nHello\n"
```

#### ANSI 终端输出

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const ansi = Bun.markdown.render("# Hello\n\nThis is **bold** and *italic*", {
  heading: (children, { level }) => `\x1b[1;4m${children}\x1b[0m\n`,
  paragraph: children => children + "\n",
  strong: children => `\x1b[1m${children}\x1b[22m`,
  emphasis: children => `\x1b[3m${children}\x1b[23m`,
});
```

#### 嵌套列表编号

`listItem`回调函数接收渲染标记所需的所有内容——无需后期处理：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = Bun.markdown.render("1. first\n   1. sub-a\n   2. sub-b\n2. second", {
  listItem: (children, { index, depth, ordered, start }) => {
    const n = (start ?? 1) + index;
    // 1. 2. 3. at depth 0, a. b. c. at depth 1, i. ii. iii. at depth 2
    const marker = !ordered
      ? "-"
      : depth === 0
        ? `${n}.`
        : depth === 1
          ? `${String.fromCharCode(96 + n)}.`
          : `${toRoman(n)}.`;
    return "  ".repeat(depth) + marker + " " + children.trimEnd() + "\n";
  },
  // Prepend a newline so nested lists are separated from their parent item's text
  list: children => "\n" + children,
});
// 1. first
//   a. sub-a
//   b. sub-b
// 2. second
```

#### 代码块语法高亮

````ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = Bun.markdown.render("```js\nconsole.log('hi')\n```", {
  code: (children, meta) => {
    const lang = meta?.language ?? "";
    return `<pre><code class="language-${lang}">${children}</code></pre>`;
  },
});
````

### 解析器选项

解析器选项作为第三个参数传入：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = Bun.markdown.render(
  "Visit www.example.com",
  {
    link: (children, { href }) => `[${children}](${href})`,
    paragraph: children => children,
  },
  { autolinks: true },
);
```

***

## `Bun.markdown.react()`

将 Markdown 直接渲染为 React 元素。返回一个 `<Fragment>`，可以作为组件返回值使用。

```tsx theme={"theme":{"light":"github-light","dark":"dracula"}}
function Markdown({ text }: { text: string }) {
  return Bun.markdown.react(text);
}
```

### 服务端渲染

支持 `renderToString()` 和 React 服务端组件：

```tsx theme={"theme":{"light":"github-light","dark":"dracula"}}
import { renderToString } from "react-dom/server";

const html = renderToString(Bun.markdown.react("# Hello **world**"));
// "<h1>Hello <strong>world</strong></h1>"
```

### 组件替代

通过第二个参数传入以标签名为键的自定义 React 组件，替换任意 HTML 元素：

```tsx theme={"theme":{"light":"github-light","dark":"dracula"}}
function Code({ language, children }) {
  return (
    <pre data-language={language}>
      <code>{children}</code>
    </pre>
  );
}

function Link({ href, title, children }) {
  return (
    <a href={href} title={title} target="_blank" rel="noopener noreferrer">
      {children}
    </a>
  );
}

function Heading({ id, children }) {
  return (
    <h2 id={id}>
      <a href={`#${id}`}>{children}</a>
    </h2>
  );
}

const el = Bun.markdown.react(
  content,
  {
    pre: Code,
    a: Link,
    h2: Heading,
  },
  { headings: { ids: true } },
);
```

#### 可覆盖元素列表

解析器产生的每个 HTML 标签都可以被替换：

| 选项           | Props                        | 描述                                       |
| ------------ | ---------------------------- | ---------------------------------------- |
| `h1`–`h6`    | `{ id?, children }`          | 标题。启用 `headings: { ids: true }` 时带有 `id` |
| `p`          | `{ children }`               | 段落                                       |
| `blockquote` | `{ children }`               | 引用                                       |
| `pre`        | `{ language?, children }`    | 代码块。`language` 是信息字符串（例如 `"js"`）         |
| `hr`         | `{}`                         | 分割线（无子元素）                                |
| `ul`         | `{ children }`               | 无序列表                                     |
| `ol`         | `{ start, children }`        | 有序列表。`start` 是起始编号                       |
| `li`         | `{ checked?, children }`     | 列表项。任务列表项带 `checked`                     |
| `table`      | `{ children }`               | 表格                                       |
| `thead`      | `{ children }`               | 表头                                       |
| `tbody`      | `{ children }`               | 表体                                       |
| `tr`         | `{ children }`               | 表格行                                      |
| `th`         | `{ align?, children }`       | 表头单元格                                    |
| `td`         | `{ align?, children }`       | 表格单元格                                    |
| `em`         | `{ children }`               | 斜体强调 (`*text*`)                          |
| `strong`     | `{ children }`               | 加粗 (`**text**`)                          |
| `a`          | `{ href, title?, children }` | 链接                                       |
| `img`        | `{ src, alt?, title? }`      | 图像（无子元素）                                 |
| `code`       | `{ children }`               | 行内代码                                     |
| `del`        | `{ children }`               | 删除线 (`~~text~~`)                         |
| `br`         | `{}`                         | 硬换行（无子元素）                                |

### React 18 及更早版本

默认情况下，元素使用 `Symbol.for('react.transitional.element')` 作为 `$$typeof` 符号。对于 React 18 及更早版本，在选项（第三参数）中传入 `reactVersion: 18`：

```tsx theme={"theme":{"light":"github-light","dark":"dracula"}}
function Markdown({ text }: { text: string }) {
  return Bun.markdown.react(text, undefined, { reactVersion: 18 });
}
```

### 解析器选项

所有[解析器选项](#options)作为第三个参数传入：

```tsx theme={"theme":{"light":"github-light","dark":"dracula"}}
const el = Bun.markdown.react("## Hello World", undefined, {
  headings: { ids: true },
  autolinks: true,
});
```
