Skip to content

Markdown

以框架无关的 Web Component 渲染 Markdown——包括 逐 token 到达的 AI 输出<r-markdown> 参考 Vercel 的 Streamdown 设计:文本流式到达时会即时闭合半截的 **粗体`代码、链接和 $$ 公式,把文档切成块并 只重渲染发生变化的那一块,长回复不会因为每个 token 都从头重新解析。

围栏 ```mermaid 代码块会变成 <r-mermaid>,公式变成 <r-math>,代码可用 shiki 高亮——这三者都在内容首次需要时才懒加载。输出经 DOMPurify 净化。

何时使用:需要展示不完全可控的 Markdown——聊天回复、LLM 流式输出、用户评论、文档——并希望开箱即得流式、代码/图表/公式支持与安全 HTML,而不必自己拼装解析器、净化器和高亮器。

快速开始

html
<r-markdown copy highlight content="# 你好 ..."></r-markdown>
js
import 'ranui'; // 或独立入口:
import 'ranui/markdown';

内容来源依次为:content 属性(property,推荐)——不会反射到 attribute,流式写入长文本不会抖动 DOM;content attribute;元素的文本内容:

js
const el = document.querySelector('r-markdown');
el.setAttribute('caret', ''); // 流式期间显示闪烁光标
for await (const chunk of stream) {
  el.content += chunk; // 只有最后一块会重渲染
}
el.removeAttribute('caret');

流式渲染

mode="streaming"(默认)会先用 remend(从 Streamdown 抽出的"未完成 Markdown 补全器")处理文本:半截的 **粗体 渲染成粗体而不是裸星号,[文字](https://exa 在 URL 闭合前显示为纯文本,- 不会把上一段变成标题……。已完成的文档可设 mode="static" 跳过这一步、整体一次渲染。

html
<r-markdown caret content="半截的 *斜体*、`行内代码`,以及**还在到达中的粗体"></r-markdown>
  • 光标caret 在最后一块后显示闪烁的 caret="circle" 显示 。当代码围栏尚未闭合或最后一块是表格时自动隐藏。
  • 未闭合的代码围栏 在闭合前保持纯文本(不会高亮闪烁、不会渲染半个图表),期间容器带 data-incomplete

代码块

每个代码块都有语言标签头部,可选加复制 / 下载按钮。加 highlightshiki 高亮(懒加载,语言按需加载;默认 github-light / github-dark,跟随页面主题)。

html
<r-markdown copy download line-numbers highlight></r-markdown>
<!-- 指定主题:亮色 暗色 -->
<r-markdown highlight="vitesse-light vitesse-dark"></r-markdown>

Mermaid 与公式

  • ```mermaid<r-mermaid>(带全屏;copy / download 会透传)。
  • $$…$$\[…\]```math → 块级 <r-math>\(…\) → 行内。单美元 $…$显式开启 inline-math,因为它与货币符号歧义。

API 参考

属性

属性类型默认值说明
contentstringMarkdown 源。content property 优先且不反射;否则回退到元素文本内容。
mode'streaming' | 'static''streaming'streaming 补全未闭合 Markdown 并按块 diff;static 原样整体渲染一次。
caretboolean / 'circle'最后一块后的闪烁光标(circle 时为 )。
copyboolean代码块复制按钮(也透传给内嵌的 <r-mermaid>)。
downloadboolean代码块下载按钮(按语言生成 code.<ext>)。
line-numbersboolean代码块行号。
highlightboolean / "亮色 暗色" 主题名shiki 语法高亮。空值 → github-light github-dark;一个名字 → 两者相同;两个名字 → 亮色 / 暗色。
inline-mathboolean$…$ 当作行内公式(\(…\) 始终是)。
link-targetstring'_blank'外部链接的 target(附带 rel="noopener noreferrer")。_self 不处理链接。页内 #锚点 永远不加。
theme'auto' | 'light' | 'dark''auto'高亮 / 图表主题。auto 跟随页面(.dark[data-ran-theme],否则 prefers-color-scheme)。
sheetstring注入 shadow root 的额外 CSS。
label-*string英文覆盖控件文案:label-copylabel-download

对应的 property:contentmodecaretcopyabledownloadablelineNumbershighlightinlineMathlinkTargetthemesheet

事件

所有事件均冒泡并穿透 shadow 边界(composed)。

事件detail触发时机
render{ blocks: number, changed: number }一次渲染至少改变了一个块
copied{ kind: 'code', language, code }复制了某个代码块
download{ kind: 'code', language, filename }下载了某个代码块
error{ message: string }解析 / 渲染失败(同时就地显示)

CSS Parts

Part说明
markdown最外层容器。
body块容器。
block每个渲染出的块。
code代码块容器。
code-header代码块的语言 / 操作栏。
code-lang语言标签。
code-actions操作按钮组。
button每个复制 / 下载按钮。
table可横向滚动的表格外层。
error渲染失败时的错误框。
css
r-markdown::part(code) {
  border-radius: 8px;
}

CSS 变量

在元素上覆盖(每个都先回退到语义 token,再回退到字面量): --ran-markdown-color--ran-markdown-font-size--ran-markdown-line-height--ran-markdown-gap--ran-markdown-heading-color--ran-markdown-link-color--ran-markdown-inline-code-bg--ran-markdown-code-bg--ran-markdown-code-border--ran-markdown-code-radius--ran-markdown-code-font-size--ran-markdown-mono-font--ran-markdown-blockquote-border--ran-markdown-table-border--ran-markdown-table-header-bg--ran-markdown-caret--ran-markdown-caret-color--ran-markdown-button-color--ran-markdown-error-color

说明

  • 懒加载:解析器 chunk(marked + DOMPurify + remend)在首次渲染时加载;shiki、mermaid、Temml 各自只在内容用到时才加载。不渲染 Markdown 的应用零成本。
  • 净化:Markdown 里的原始 HTML 会经过 DOMPurify——脚本、事件属性、javascript: URL、<style>、表单与 iframe 都会被移除。任务列表的复选框会保留。
  • 按块 diff 以位置为 key,因此未变化块内的 DOM 状态(打开的全屏图表、滚动过的表格)在流式更新中得以保留。文档只 lex 一次、每块用自己的 token 渲染,因此链接引用定义可以跨块解析([文字][id] 在一块、[id]: url 在另一块)。
  • GFM 脚注[^1]不支持——marked 没有脚注 tokenizer,标记会原样渲染成文本。
  • shiki 由你自己的安装解析:ES 构建保留裸的 import('shiki'),由你的打包器分包,只下载代码围栏实际用到的语法。shiki 是 ranui 的普通依赖,npm i ranui 就已带上,无需额外安装。
  • 独立 IIFEdist/iife/markdown.iife.js 没有模块解析器,因此改为内联 mermaid、Temml 以及 shiki 的 web 语言包(约 50 种常见语言)。想要完整语言覆盖且体积更小,请用 ES 入口(ranui/markdown)。

Released under the MIT License.