Slate logo

Slate

完全可定制的富文本编辑框架,以模块化和灵活的架构著称。

富文本编辑器可定制模块化React

Slate 是完全可定制的富文本编辑框架,提供原语而非预设,基于嵌套 JSON 节点树数据模型,所有编辑器行为通过插件实现,被 Discord、Grafana、GitBook 等产品采用,极致可定制性是其最大优势。

Slate

完全可定制的富文本编辑框架,以模块化和灵活的架构著称。

技术简介说明

Slate 是由 Ian Storm Taylor 创建的可定制富文本编辑框架。它的核心设计哲学是"提供原语而非预设"——Slate 不提供任何开箱即用的功能(包括加粗、列表等),而是给开发者提供构建任何编辑器体验所需的全部工具。

Slate 的数据模型基于嵌套的 JSON 节点树,每个节点可以是 Element(容器)、Text(叶子节点)或 Editor(根节点)。这种简洁而强大的模型使得开发者可以定义任意复杂的文档结构,同时保持数据序列化/反序列化的简单性。

自 2016 年发布以来,Slate 被 Discord、Grafana、GitBook、Taskade 等知名产品采用。其最大的优势在于极致的可定制性——没有任何编辑器行为是硬编码的,所有功能都通过插件和自定义渲染实现。2024–2026 年间,Slate 持续迭代至 v0.124+,同时其上层框架 Plate.js 已成为最活跃的 Slate 生态项目。

基本信息

  • 官网https://www.slatejs.org/
  • GitHubhttps://github.com/ianstormtaylor/slate
  • License:MIT
  • 最新版本:slate 0.124.1 / slate-react 0.125.1(2026 年中)
  • 主要维护者:Ian Storm Taylor(个人项目,社区驱动)
  • GitHub Stars:~31,600+
  • npm 周下载量:~2.5M(slate 核心包)
  • 框架支持:React(主要)/ 通用(核心层)

快速上手

安装

# 核心包
npm install slate slate-react slate-history
 
# slate-dom 是 slate-react 的 DOM 层(2024 年拆分)
npm install slate-dom
 
# TypeScript 类型(已内置)
# slate 从 0.65+ 开始内置 TypeScript 类型

基础配置

import { createEditor, Descendant } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
import { withHistory } from 'slate-history'
 
// 初始文档内容
const initialValue: Descendant[] = [
  {
    type: 'paragraph',
    children: [{ text: 'Hello World!' }],
  },
]
 
// 创建编辑器(组合增强函数)
const editor = withHistory(withReact(createEditor()))

最小示例(React)

import React, { useMemo, useState } from 'react'
import { createEditor, Descendant } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
import { withHistory } from 'slate-history'
 
const initialValue: Descendant[] = [
  { type: 'paragraph', children: [{ text: 'A line of text in a paragraph.' }] },
]
 
export default function App() {
  const editor = useMemo(() => withHistory(withReact(createEditor())), [])
  const [value, setValue] = useState<Descendant[]>(initialValue)
 
  return (
    <Slate editor={editor} initialValue={value} onChange={setValue}>
      <Editable
        placeholder="开始编辑..."
        style={{
          minHeight: '200px',
          padding: '10px',
          border: '1px solid #ccc',
          outline: 'none',
        }}
      />
    </Slate>
  )
}

自定义元素渲染

import { RenderElementProps, RenderLeafProps } from 'slate-react'
 
// 自定义元素渲染
const renderElement = (props: RenderElementProps) => {
  switch (props.element.type) {
    case 'heading-one':
      return <h1 {...props.attributes}>{props.children}</h1>
    case 'heading-two':
      return <h2 {...props.attributes}>{props.children}</h2>
    case 'quote':
      return <blockquote {...props.attributes}>{props.children}</blockquote>
    default:
      return <p {...props.attributes}>{props.children}</p>
  }
}
 
// 自定义叶子节点渲染(加粗、斜体等)
const renderLeaf = (props: RenderLeafProps) => {
  let { children } = props
  if (props.leaf.bold) children = <strong>{children}</strong>
  if (props.leaf.italic) children = <em>{children}</em>
  if (props.leaf.underline) children = <u>{children}</u>
  if (props.leaf.code) children = <code>{children}</code>
  return <span {...props.attributes}>{children}</span>
}
 
// 使用
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />

核心概念与架构

架构设计

Slate 的架构基于以下核心原则:

  1. 一等公民的 JSON 模型:文档是纯 JSON,易于序列化和传输
  2. 框架无关的核心slate 核心包不包含任何 DOM 代码
  3. 插件即增强函数:插件是接收编辑器并返回增强编辑器的函数
  4. 嵌套文档模型:支持任意深度的节点嵌套
  5. 不可变操作:通过 Operation 层实现可预测的状态变更

核心概念

  • Editor:根节点,同时也是编辑器实例,包含所有插件方法
  • Element:包含子节点的容器节点,可以是 block 或 inline
  • Text:叶子节点,包含文本内容和格式标记(marks)
  • Node:Editor、Element、Text 的统称
  • Path:定位节点的数字数组路径,如 [0, 1, 2]
  • Point:Path + offset,精确定位到文本中的某个字符位置
  • Range:两个 Point 组成的范围(锚点 anchor + 焦点 focus)
  • Location:Path、Point 或 Range 的统称
  • Operation:8 种原子操作(insert_text、remove_text、insert_node 等)
  • Transform:由一组 Operation 组成的高级操作

插件模型

Slate 的插件是高阶函数(Higher-Order Functions):

import { Editor } from 'slate'
 
const withImages = (editor: Editor) => {
  const { isVoid, insertData } = editor
 
  editor.isVoid = (element) => {
    return element.type === 'image' ? true : isVoid(element)
  }
 
  editor.insertData = (data) => {
    const files = data.files
    if (files && files.length > 0) {
      // 处理图片粘贴
      for (const file of files) {
        const [mime] = file.type.split('/')
        if (mime === 'image') {
          const url = URL.createObjectURL(file)
          insertImage(editor, url)
        }
      }
    } else {
      insertData(data)
    }
  }
 
  return editor
}
 
// 使用
const editor = withImages(withHistory(withReact(createEditor())))

核心特性

  • 极致可定制:所有编辑器行为均可通过插件和渲染函数覆盖
  • 嵌套文档模型:支持任意深度的节点嵌套结构
  • JSON 序列化:文档是纯 JSON,易于存储、传输和版本控制
  • 插件即函数:简单而强大的插件模型,无黑盒
  • 框架分离:核心层与 DOM/React 层分离(slate-dom 包)
  • Redux 风格选择器:slate-react 的选择器防止不必要的重渲染
  • 撤销/重做:通过 slate-history 提供完整的操作历史
  • 协作编辑:通过 slate-yjs 与 Yjs 集成实现实时协作
  • Scrubber 接口:新特性,允许遮蔽异常文本中的用户数据
  • TypeScript 支持:完整的类型定义

生态图

核心包

包名说明
slate核心模型和编辑器逻辑(框架无关)
slate-reactReact 组件和 hooks
slate-domDOM 层(从 slate-react 拆分)
slate-history撤销/重做功能
slate-hyperscriptJSX 测试支持

上层框架生态

  • Plate.js:最活跃的 Slate 上层框架,提供 40+ 插件和 shadcn/ui 组件
    • 最新版本:v52+(2025–2026)
    • AI 集成、MCP 支持
    • 开箱即用的模板和组件

协作编辑

  • slate-yjs:Yjs 与 Slate 的桥接层
  • Liveblocks:提供 Slate 协作集成方案

社区资源

适用场景

  • 高度定制的编辑器:需要完全控制编辑器的每个行为(如 Discord 的消息编辑器)
  • 非标准编辑体验:如可拖拽的块编辑器、代码+富文本混合编辑器
  • React 项目:Slate 的 React 集成最成熟(slate-react)
  • 数据驱动的编辑器:利用 JSON 模型实现文档的程序化操作
  • 实时协作编辑器:通过 slate-yjs 或 Liveblocks 集成
  • 复杂文档结构:需要深度嵌套的文档模型(如表格中的表格)
  • CMS 内容编辑:与 Headless CMS 集成的内容编辑场景

开发与工程化

开发流程

# 克隆仓库
git clone https://github.com/ianstormtaylor/slate.git
cd slate
 
# 安装依赖(使用 yarn workspaces)
yarn install
 
# 构建
yarn build
 
# 测试
yarn test
 
# 运行示例
yarn dev

自定义插件开发模式

// 典型的插件开发模式
const withMyFeature = (editor: Editor) => {
  // 1. 覆盖编辑器方法
  const { normalizeNode, isVoid, isInline } = editor
 
  // 2. 添加自定义逻辑
  editor.normalizeNode = (entry) => {
    // 自定义规范化规则
    normalizeNode(entry) // 记得调用原始方法
  }
 
  // 3. 添加新方法
  editor.insertMention = (character: string) => {
    // ...
  }
 
  return editor
}

测试策略

// 使用 slate-hyperscript 创建测试文档
/** @jsx jsx */
import { jsx } from 'slate-hyperscript'
 
const editor = (
  <editor>
    <element type="paragraph">
      <text>Hello <text bold>World</text></text>
    </element>
  </editor>
)

性能与安全

性能特点

  • Redux 风格选择器:slate-react 的选择器可以阻止每次按键时的全量重渲染
  • 增量更新:DOM 更新基于 diff,仅修改变化的部分
  • 大文档挑战:Slate 默认不做虚拟滚动,大文档需要额外优化

性能优化

  • 使用 useSlateSelector 避免不必要的组件重渲染
  • 对大文档考虑虚拟化渲染(如 react-virtuoso)
  • 合理使用 React.memo 包裹自定义元素组件
  • 避免在 onChange 中执行重计算

安全注意

  • 渲染自定义元素时注意 XSS 防护
  • 对用户粘贴的 HTML 内容进行消毒
  • 服务端序列化时避免执行用户提供的脚本
  • 使用 DOMPurify 处理编辑器输出

技术对比

特性SlateTipTapLexicalQuillProseMirror
架构无头框架无头框架无头框架传统 WYSIWYG底层框架
框架React 为主React/Vue/SvelteReact 为主框架无关框架无关
开箱即用⚠️ 极少✅ 中等⚠️ 较少✅ 较多❌ 极少
文档模型JSON 嵌套树ProseMirror 模型层级节点Delta/BlotProseMirror 模型
插件模型高阶函数扩展系统Command/PluginModulePlugin
协作编辑slate-yjsy-tiptap(付费)内置(有限)需自建prosemirror-collab
纯装饰
1.0 版本❌ 仍在 beta✅ 3.0 稳定❌ 0.x✅ 2.0✅ 稳定
学习曲线较陡中等较陡陡峭

最佳实践

  1. 考虑使用 Plate.js:除非需要极致的底层控制,Plate.js 提供了一站式解决方案
  2. TypeScript 类型扩展:使用模块增强扩展内置类型
    import { BaseElement } from 'slate'
    declare module 'slate' {
      interface CustomTypes {
        Element: BaseElement & { type: 'paragraph' | 'heading' }
      }
    }
  3. 插件组合顺序重要withHistory(withReact(createEditor())) 的顺序会影响行为
  4. 规范化(Normalization)是关键:理解 Slate 的规范化机制是正确使用 Slate 的关键
  5. 避免直接修改 Editor 对象:使用 Transforms API 进行文档操作
  6. 协作编辑从规划开始:如果需要协作,在数据模型设计阶段就考虑 CRDT 兼容性
  7. 外部状态更新:通过 Editor.insertText 等 Transform 方法而非直接修改 value

技术局限与边界

  • 仍在 Beta:发布多年但至今未发布 1.0,API 可能仍有变动
  • React 绑定:核心虽框架无关,但实际使用几乎绑定 React(无官方 Vue/Angular 支持)
  • 缺少内置功能:没有内置的加粗、列表等功能,一切从底层开始构建
  • Android IME 问题:Android 输入法的兼容性历史上存在较多问题
  • 大文档性能:默认无虚拟滚动,需要自行优化
  • 迁移成本:从 Slate 迁移到其他编辑器(或反向迁移)需要处理数据模型差异
  • 社区活跃度波动:核心维护者投入不稳定,社区有时质疑项目是否"dead"
  • Plate.js 生态分裂:Plate 的快速发展可能导致 Slate 核心被忽视

学习资源

2026 年现状

最新版本

  • slate:0.124.1(~2026 年 4 月)
  • slate-react:0.125.1(~2026 年 7 月)
  • slate-dom:独立包(从 slate-react 拆分,~2024–2025)

发展趋势

  • slate-dom 拆分:DOM 层独立为 slate-dom 包,为非 React 框架适配铺路
  • Plate.js 主导:Plate.js(v52+)已成为 Slate 生态最活跃的项目
    • AI 集成、MCP 支持、shadcn/ui 组件
    • Git 兼容的版本控制
  • Redux 风格选择器:新增选择器机制防止每次按键的重渲染
  • Scrubber 接口:新增数据遮蔽接口用于隐私保护
  • 发布流程改进:采用 changesets 进行结构化版本管理

社区活跃度

  • GitHub Stars:~31,600+
  • npm 周下载量:~2.5M
  • 1.0 版本 milestone 存在但无明确日期(11/20 issues 已完成)
  • 社区贡献持续,PR 活跃(#5937 等持续有新 PR)

定位总结

Slate 在 2026 年依然是最灵活的可定制编辑框架,但需要注意其仍为 Beta 状态且以 React 为主。对于新项目,如果不需要极致的底层控制,建议评估 Plate.js 作为起点。如果需要跨框架支持(Vue/Angular),TipTap 可能是更好的选择。