Tiptap 编辑器深度解析:Headless 富文本框架的扩展架构、核心 API 与本地实战
Tiptap 是一个无界面(headless)、框架无关的富文本编辑器框架,基于 ProseMirror 构建,通过扩展(Extension)机制实现从基础文本样式到复杂块级编辑能力的自由组合。本文以 Tiptap 仓库根目录 README.md 为主线,结合 packages/core 的源码实现与 demos 中的真实示例,完整梳理其设计哲学、包生态结构、EditorOptions 配置体系与扩展开发机制,帮助你在本地搭建、运行并二次开发 Tiptap 编辑器。
一、Tiptap 是什么:Headless、框架无关、扩展驱动
根据仓库 README.md 的定义,Tiptap Editor 是一个 headless、framework-agnostic(框架无关)的富文本编辑器,核心特征有四点:
- Headless(无内置界面):Tiptap 不附带任何固定 UI,不需要类名覆盖或代码 hack 来改样式,设计自由度完全交给使用者;
- 框架无关:同一套核心可以在 Vue、React、Svelte 或纯 JavaScript 环境中集成,无兼容性问题;
- 基于扩展:从简单文本样式到拖拽块编辑,功能均由扩展提供。README 提到官方文档与社区提供了上百个扩展可供选择;
- UX 完全可控:编辑器允许开发者自定义扩展与节点(Node),把交互体验的定义权交给应用层。
在源码层面,这一理念对应 packages/core 包——它被描述为 headless rich text editor(见 packages/core/package.json),当前版本为 3.30.3。Tiptap 的底层构建在 ProseMirror 之上:仓库通过 packages/pm 这一 workspace 包对 ProseMirror 各子模块(model、state、view、schema-list、tables 等)做统一再导出,所有 @tiptap/* 包都依赖 @tiptap/pm 而非直接引用上游包,从包管理角度屏蔽了 ProseMirror 的模块拆分细节。
此外,README 指出 Tiptap 与开源协作后端 Hocuspocus 共同构成 Tiptap Suite 的基础,后者围绕 Yjs 的 CRDT 能力构建。本仓库中对应的是 packages/extension-collaboration 等协作相关扩展包。
二、仓库结构:一个多包(monorepo)生态
从仓库目录结构看,Tiptap 是一个典型的 pnpm workspace monorepo,分为四大板块:
2.1 packages/:核心与官方扩展
这是最重要的部分,包含:
- 核心:packages/core(编辑器引擎、扩展基类、命令系统)、packages/extensions(扩展集合)、packages/starter-kit(开箱即用的扩展套件);
- 框架适配层:packages/react、packages/vue-2、packages/vue-3;
- 序列化/静态渲染:packages/markdown、packages/html、packages/static-renderer、packages/ai-toolkit(含流式输出 reveal 等 AI 场景工具);
- 具体功能扩展:按
extension-*命名组织,如 packages/extension-bold、packages/extension-heading、packages/extension-table、packages/extension-link、packages/extension-list、packages/extension-collaboration、packages/extension-collaboration-caret、packages/extension-drag-handle、packages/extension-mention、packages/extension-emoji、packages/extension-youtube 等数十个。
2.2 packages-deprecated/:废弃包的兼容层
packages-deprecated 下保留了 extension-character-count、extension-history、extension-placeholder、extension-task-item 等旧包。例如历史上独立的 ListItem / TableCell / TaskList 等,如今已合并进 packages/extension-list 与 packages/extension-table 这类聚合包中——废弃包的存在说明 Tiptap 在扩展粒度上做过重组,但仍维持向后兼容。
2.3 demos/:可运行的官方示例应用
demos 是一个 Vite + 多框架的示例站点,目录按功能域划分:Examples/(默认、协作、无障碍等)、Extensions/(DragHandle、FindAndReplace、TableOfContents 等)、Marks/(Bold、Link、Underline…)、Nodes/(Heading、CodeBlock、Youtube…)、Tutorials/(从 textarea 到 Tiptap 再到 Yjs 协作的渐进式教程)、Experiments/ 等。每个示例通常包含 React(.jsx/.tsx)与 Vue(.vue)两套实现,这正是 README 所宣称的"框架无关"的直观体现。
2.4 scripts/ 与工程配置
根目录 package.json 定义了整套工程脚本:pnpm dev(启动 demos)、pnpm build、pnpm test:unit(基于 vp test)、pnpm test:e2e(Playwright)、pnpm lint / pnpm format(oxlint / oxfmt)等。环境要求为 Node >= 24,包管理器固定为 pnpm@11.2.2(packageManager 字段声明)。
三、核心引擎:@tiptap/core 的 Editor 与 EditorOptions
3.1 Editor 类
编辑器入口是 packages/core/src/Editor.ts 中的 Editor 类(自 L59 起)。关键实现事实:
Editor继承自EventEmitter(编辑器事件系统),内部持有CommandManager(命令系统)、ExtensionManager(扩展管理器)、ProseMirror 的Schema与EditorView、EditorState;- 默认选项在 L92-L120 定义,例如
content: ''、extensions: []、autofocus: false、editable: true、enableInputRules: true、enablePasteRules: true等; - 实例具备
instanceId(随机生成)、isInitialized标志与extensionStorage(各扩展的持久化存储); - 内置核心扩展在构造时自动注入,包括
ClipboardTextSerializer、Commands、Delete、Drop、Editable、FocusEvents、Keymap、Paste、Tabindex、TextDirection(见 Editor.ts L11-L22 的导入),它们分别对应键盘快捷键、焦点/失焦事件、粘贴处理等基础行为。
3.2 EditorOptions 完整配置项
完整的选项类型定义在 packages/core/src/types.ts 的 EditorOptions 接口中,逐项说明如下:
| 选项 | 类型 / 取值 | 说明 |
|---|---|---|
element |
Element | { mount: HTMLElement } | ((editor) => void) | null |
编辑器挂载目标:传 Element 则追加到该元素;传 null 则不自动挂载;传函数则由其自行放置编辑器 DOM |
content |
Content |
初始内容,支持 HTML 字符串、JSON 对象或 JSON 数组 |
extensions |
Extensions |
使用的扩展列表 |
injectCSS |
boolean |
是否注入基础 CSS |
injectNonce |
string | undefined |
注入样式时使用的 CSP nonce |
autofocus |
FocusPosition |
初始聚焦位置 |
editable |
boolean |
是否可编辑(只读模式设为 false) |
textDirection |
'ltr' | 'rtl' | 'auto' | undefined |
全文本方向策略:auto 会按内容检测设置 dir 属性 |
editorProps |
EditorProps |
透传给 ProseMirror EditorView 的 props |
parseOptions |
ParseOptions |
内容解析选项 |
coreExtensionOptions |
对象 | 核心扩展细粒度配置:clipboardTextSerializer.blockSeparator、tabindex.value、delete.async / delete.filterTransaction |
enableInputRules |
EnableRules |
是否启用输入规则(如 Markdown 快捷输入) |
enablePasteRules |
EnableRules |
是否启用粘贴规则 |
enableCoreExtensions |
boolean | Partial<Record<...>> |
布尔值全量开关;也可传对象按名称关闭单个核心扩展,如 { keymap: false } |
enableContentCheck |
boolean,默认 false |
初始化时检查内容合法性,非法时触发 contentError 事件 |
emitContentError |
boolean,默认 false |
不做阻断性检查,但保留内容并触发 contentError 警告 |
onBeforeCreate / onCreate / onMount / onUnmount |
回调 | 生命周期钩子 |
onUpdate / onSelectionUpdate / onTransaction |
回调 | 内容、选区、事务变化回调 |
onFocus / onBlur |
回调 | 焦点事件回调 |
onDestroy |
回调 | 销毁回调 |
onPaste / onDrop / onDelete |
回调 | 粘贴、拖入、删除的内容拦截回调 |
enableExtensionDispatchTransaction |
boolean,默认 true |
是否允许扩展自定义 dispatchTransaction 钩子 |
Editor.ts L119-L120 还展示了 onContentError 的默认行为是 直接抛出 error(throw error),意味着开启 enableContentCheck 后若不加自定义处理,非法内容会直接中断初始化——这是使用时的一个重要注意点。
3.3 core 包的公开 API
从 packages/core/src/index.ts 可以看出 @tiptap/core 的完整导出面:Editor、Extension、Node、Mark、NodeView、MarkView、InputRule、PasteRule、CommandManager、Tracker,以及内置的 commands 命名空间、jsx-runtime(createElement / Fragment,用于在 JS 环境中以 JSX 描述文档节点)等。扩展作者几乎只需要依赖这些导出即可编写新扩展。
四、扩展机制:Extension 的 create / configure / extend 三件套
README 强调 Tiptap "通过扩展定制与扩展能力",其机制实现于 packages/core/src/Extension.ts(L16-L59):
Extension.create(config)(L27-L33):静态工厂方法,接受配置对象或返回配置对象的函数,返回Extension实例。这是所有自定义扩展的入口;configure(options)(L35-L37):用新选项创建同一扩展的配置化副本,常用于"给扩展传参"而不改变其行为;extend(extendedConfig)(L39-L58):基于现有扩展派生新扩展,可在派生时覆盖addCommands、addKeyboardShortcuts、addAttributes等任意配置段,同样支持函数式配置。
Extension 继承自 Extendable(packages/core/src/Extendable.ts),后者统一处理 name / option / storage 合并逻辑;Node 与 Mark 类(packages/core/src/Node.ts、packages/core/src/Mark.ts)分别继承该体系,形成"扩展—节点—标记"三层结构。
以仓库内一个最小扩展为例,packages/extension-strike/src 展示了如何定义一个 Mark 类扩展并注册 strike 命令与 HTML 序列化规则;而 packages/extension-heading/src 则展示了 Node 扩展如何声明 level 属性。两者都可配合 __tests__ 目录下的用例(如 packages/extension-strike/tests 的测试文件)验证行为。
五、快速上手:StarterKit 与仓库内真实示例
5.1 StarterKit 包含什么
packages/starter-kit/package.json 的依赖列表就是它的完整内容:extension-document、extension-paragraph、extension-text(文档结构三件套)、extension-heading、extension-blockquote、extension-bullet-list / extension-ordered-list / extension-list / extension-list-item(标题、引用与列表)、extension-bold / extension-italic / extension-strike / extension-underline / extension-code(行内标记)、extension-code-block、extension-horizontal-rule、extension-hard-break、extension-link,以及 extension-dropcursor / extension-gapcursor(拖放与空位光标)等。也就是说,一个"基础编辑器"≈ 一个 StarterKit。
5.2 官方默认示例(React 版)
demos/src/Examples/Default/React/index.tsx 展示了标准用法:
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { TextStyleKit } from '@tiptap/extension-text-style'
const extensions = [TextStyleKit, StarterKit]
export default () => {
const editor = useEditor({
extensions,
content: `<h2>Hi there,</h2><p>this is a <em>basic</em> example…</p>`,
})
return (
<>
<MenuBar editor={editor} />
<EditorContent editor={editor} />
</>
)
}
要点:内容可以是 HTML 字符串;MenuBar 是演示用的自绘工具栏(headless 的体现);同一示例在 demos/src/Examples/Default/Vue 中有 Vue 实现,在 demos/src/Examples/Default/Svelte 中有 Svelte 实现,可对比三种框架适配层的 API 差异(useEditor 响应式 ref 等)。
纯 JS / 无框架场景下,直接使用 @tiptap/core:new Editor({ element, extensions, content }),element 参数语义见前文 EditorOptions 表。
六、在本地运行 Tiptap 仓库
以下命令均基于根目录 package.json 的 scripts 定义(要求 Node >= 24、pnpm 11.2.2):
pnpm install # 安装 workspace 依赖(prepare 阶段会自动运行 vp config)
pnpm dev # 启动 demos 应用(vp run start)
pnpm build # 递归构建所有 packages(vp run -r build)
pnpm test:unit # 运行单元测试(vp test)
pnpm test:e2e # Playwright 端到端测试(chromium)
pnpm lint # oxlint 静态检查
几个值得关注的工程化细节:
- 新增 demo 脚手架:scripts/make-demo.sh 通过
pnpm run make:demo运行,交互式询问 demo 名称与分类(Dev/Examples/Extensions/Experiments/Marks/Nodes),并从 demos/src/Examples/Default 模板复制目录(见 CONTRIBUTING.md "Create a new demo" 一节); - 发布流程:使用 Changesets 管理版本,
pnpm run publish会先vp run build再执行changeset publish;CONTRIBUTING.md 中说明新包需要手动首发并配置 NPM trusted publishing(provenance)后才能被 CI 自动发布; - 测试分层:
packages/*/__tests__下是大量按功能命名的单测(如 packages/core/tests/setContent.spec.ts、packages/core/tests/insertContent.spec.ts、packages/core/tests/isActive.spec.ts),配合demos下的 Playwright e2e(配置见 playwright.config.ts)构成双保险。
七、协作编辑与 Tiptap Suite
README 专设 "Make your editor collaborative" 一节:协作能力由开源后端 Hocuspocus 提供,其核心是 Yjs CRDT;编辑器与 Hocuspocus 共同构成 Tiptap Suite 的基础。
在仓库中对应的实现有:
- packages/extension-collaboration:把 Yjs 的
Y.Doc与 ProseMirror 状态桥接(含 5 个源文件与 2 个测试文件); - packages/extension-collaboration-caret:远程用户光标渲染;
- packages/extension-unique-id:协作场景下为节点补充唯一 ID(其
__tests__中含 YDoc 相关用例,对应 demos/src/Extensions/UniqueIDWithYdoc 示例)。
README 同时提到 Pro Extensions(商用订阅扩展),覆盖协作编辑、评论、版本管理、文档转换与 AI 相关功能;仓库中 packages/ai-toolkit 则代表了开源侧的 AI 工具能力(如 streaming-reveal 流式输出渐显,见 packages/ai-toolkit/src/streaming-reveal.ts 及其测试 packages/ai-toolkit/tests/streaming-reveal.spec.ts)。
八、社区、贡献规范与许可
- 贡献指南:CONTRIBUTING.md 要求提交前运行测试与 linter、为包变更附带 Changeset、PR 关联已指派的 issue、AI 辅助生成内容须显式披露、30 天无响应会关闭 PR 等;
- 安全:漏洞报告遵循 SECURITY.md;
- 许可:项目采用 MIT 许可证,详见 LICENSE.md;
- 社区:README 引导使用者通过 GitHub Discussions 进行讨论(具体入口以仓库页面的 Discussions 区为准)。
九、小结
Tiptap 的技术定位可以概括为:"ProseMirror 之上的声明式扩展层"。packages/core 提供 Editor + Extension 双核心与完整的事件/命令体系;packages/pm 屏蔽 ProseMirror 模块细节;extension-* 包把每个功能单元化;demos 则证明同一 API 可以在 React、Vue 2/3、Svelte 与纯 JS 中互换运行。理解 EditorOptions(packages/core/src/types.ts)与 Extension.create / configure / extend(packages/core/src/Extension.ts)这两块,就掌握了在 Tiptap 生态中搭建、定制乃至贡献新扩展所需的全部核心知识。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00