字节笔记本
2026年2月21日
Slate:完全可定制的 React 富文本编辑器框架
Slate 是一个完全可定制的富文本编辑器框架,让你能够构建类似 Medium、Dropbox Paper 或 Google Docs 的富文本编辑器,而无需让代码库陷入复杂性。它基于 React 构建,采用插件化架构,所有逻辑都通过一系列插件实现,因此你不会被"核心"功能所限制。
项目简介
Slate 由 Ian Storm Taylor 创建,是一个开源的富文本编辑器框架。截至目前,该项目在 GitHub 上已获得 31.5k+ stars,拥有 3.3k+ forks,主要使用 TypeScript (87.9%) 和 JavaScript (11.4%) 编写,被超过 27 万个项目使用。
Slate 的设计灵感来源于 Draft.js、Prosemirror 和 Quill 等编辑器库,但它解决了这些库在构建复杂编辑器时遇到的诸多问题。
注意:Slate 目前处于 Beta 阶段,核心 API 已经可用,但在高级用例中可能需要提交 PR 来改进或修复一些 bug。部分 API 尚未"最终确定”,可能会随着时间推移而有破坏性变更。
为什么选择 Slate?
在创建 Slate 之前,作者尝试了 Draft.js、Prosemirror、Quill 等富文本库。虽然简单的示例很容易实现,但一旦尝试构建类似 Medium、Dropbox Paper 或 Google Docs 的编辑器,就会遇到以下深层问题:
- 编辑器的"schema"被硬编码且难以定制 - 粗体和斜体开箱即用,但评论、嵌入或更特定领域的需求则难以实现
- 程序化转换文档非常繁琐 - 用户写入可能有效,但程序化更改对于构建高级行为至关重要,却 unnecessarily 复杂
- 序列化为 HTML、Markdown 等似乎是事后考虑 - 简单地将文档转换为 HTML 或 Markdown 涉及编写大量样板代码
- 重新发明视图层似乎效率低下且受限 - 大多数编辑器使用自己的视图,而不是使用 React 等现有技术
- 协同编辑没有预先设计 - 编辑器的内部数据表示通常使其无法用于实时协同编辑用例
- 代码库是单一的,而不是小而可重用的 - 许多编辑器的代码库没有公开可以重用的内部工具
- 构建复杂的嵌套文档是不可能的 - 许多编辑器围绕简单的"扁平"文档设计
核心设计原则
Slate 通过以下原则解决上述问题:
1. 一流的插件 API
Slate 的核心逻辑都是插件。你可以完全定制编辑体验的各个方面,没有什么是被"核心"预设的。
2. 无 Schema 限制
Slate 的文档模型比大多数编辑器更开放,允许嵌套文档结构,而不需要处理异常或边缘情况。
3. 嵌套文档模型
Slate 的文档模型允许任意嵌套,可以创建复杂的富文本文档,如表格中的表格、引用块中的列表等。
4. 与 React 集成
Slate 直接构建在 React 之上,使用 React 的渲染机制,不需要学习新的视图层或模板语言。
5. 不可变数据
Slate 使用不可变数据结构,使得协同编辑、撤销/重做等功能更容易实现。
6. 核心包小巧
Slate 的核心包非常小,只包含必要的功能,其他功能通过插件添加。
7. 支持协同编辑
Slate 的数据模型从一开始就考虑了协同编辑的需求,支持 Operational Transformation 等算法。
技术栈
- TypeScript (87.9%) - 主要开发语言,提供类型安全
- React - 视图层框架
- Lerna - Monorepo 管理工具
- Yarn Workspaces - 包管理
安装指南
Slate 是一个 monorepo,分为多个 npm 包,安装方式如下:
# 使用 yarn
yarn add slate slate-react
# 或使用 npm
npm install slate slate-react
# 或使用 pnpm
pnpm add slate slate-react同时需要安装 peer dependencies:
yarn add react react-dom快速开始
以下是一个最基本的 Slate 编辑器示例:
import React, { useState } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
const App = () => {
// 创建一个 Slate 编辑器对象,在渲染之间保持稳定
const [editor] = useState(() => withReact(createEditor()))
// 初始文档内容
const initialValue = [
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
]
return (
<Slate editor={editor} initialValue={initialValue}>
<Editable />
</Slate>
)
}
export default AppTypeScript 类型定义
如果使用 TypeScript,需要添加类型声明:
import { BaseEditor, Descendant } from 'slate'
import { ReactEditor } from 'slate-react'
type CustomElement = { type: 'paragraph'; children: CustomText[] }
type CustomText = { text: string }
declare module 'slate' {
interface CustomTypes {
Editor: BaseEditor & ReactEditor
Element: CustomElement
Text: CustomText
}
}使用示例
添加事件处理
import React, { useState } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
const App = () => {
const [editor] = useState(() => withReact(createEditor()))
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return (
<Slate editor={editor} initialValue={value} onChange={setValue}>
<Editable
onKeyDown={event => {
if (event.key === '&') {
event.preventDefault()
editor.insertText('and')
}
}}
/>
</Slate>
)
}自定义渲染
const renderElement = props => {
switch (props.element.type) {
case 'code':
return <pre {...props.attributes}>{props.children}</pre>
default:
return <p {...props.attributes}>{props.children}</p>
}
}
const renderLeaf = props => {
return (
<span
{...props.attributes}
style={{ fontWeight: props.leaf.bold ? 'bold' : 'normal' }}
>
{props.children}
</span>
)
}
// 在 Editable 组件中使用
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />包结构
Slate 的代码库是 monorepo,由以下包组成:
| 包名 | 描述 | 是否必需 |
|---|---|---|
slate | Slate 编辑器的核心逻辑 | 是 |
slate-react | React 视图层组件 | 是(如果使用 React) |
slate-history | 撤销/重做历史记录插件 | 否 |
slate-hyperscript | 用于创建 Slate 文档的 Hyperscript 工具 | 否(测试用) |
官方示例
Slate 提供了丰富的示例,展示各种使用场景:
- Plain text - 纯文本编辑器
- Rich text - 富文本编辑器(粗体、斜体等)
- Markdown preview - Markdown 实时预览
- Links - 链接处理
- Images - 图片嵌入
- Tables - 表格编辑
- Mentions - @提及功能
- Embeds - 嵌入第三方内容
- Forced layout - 强制布局
- Hovering toolbar - 悬浮工具栏
- Collaborative editing - 协同编辑
所有示例都可以在 slatejs.org 查看源代码。
相关项目
基于 Slate 构建的开源项目:
- Plate - 高级 Slate 插件集合
- Slate Plugins - Slate 插件库
- Remirror - 基于 ProseMirror 和 Slate 的编辑器框架
- flomo-editor - 基于 React + Slate.js 的开源富文本编辑器
项目链接
- GitHub 仓库: https://github.com/ianstormtaylor/slate
- 官方文档: https://docs.slatejs.org/
- 在线示例: http://slatejs.org/
- Slack 社区: https://slate-slack.herokuapp.com/
许可证
Slate 使用 MIT 许可证开源。