npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zt-reactjs-tiptap

v0.1.17

Published

A powerful Markdown editor based on TipTap with Notion-like features

Readme

zt-reactjs-tiptap

基于 TipTap 的 React 富文本编辑器组件,支持 Notion 风格(斜杠命令、块状编辑)与 Headless(顶部工具栏、可嵌入自定义 UI)两种模式。

npm version license

GitHub: https://github.com/lzt-T/md-tiptap

特性

  • ✨ 丰富的文本格式化选项(粗体、斜体、下划线、删除线、行内代码)
  • 📝 支持标题(H1、H2、H3)、列表(有序/无序)、引用、代码块
  • 🖼️ 图片插入和管理(支持文件上传和 URL 插入)
  • 📊 完整表格支持(插入/删除行列、切换表头、删除表格)
  • ✅ 任务列表(带复选框的可交互待办事项)
  • 🎨 文本颜色和背景高亮
  • 🔢 数学公式支持(行内和块级 LaTeX 公式,基于 KaTeX)
  • ⚡ 斜杠命令(输入 / 快速插入各种内容块)
  • 🎯 气泡菜单(选中文本时显示格式化工具栏)
  • 🔄 撤销/重做支持
  • 📐 文本对齐(左对齐、居中、右对齐、两端对齐)
  • ⬆️⬇️ 上标/下标支持
  • 📄 HTML/DOM 转纯文本工具(与编辑器 getText() 一致)

安装

npm install zt-reactjs-tiptap
# 或
pnpm add zt-reactjs-tiptap
# 或
yarn add zt-reactjs-tiptap

使用

基础使用

import { TiptapEditor } from 'zt-reactjs-tiptap'
import 'zt-reactjs-tiptap/style.css'  // 必须导入样式

function App() {
  const [content, setContent] = useState('<p>Hello World!</p>')

  return (
    <TiptapEditor
      value={content}
      onChange={setContent}
    />
  )
}

带图片上传

import { TiptapEditor } from 'zt-reactjs-tiptap'
import 'zt-reactjs-tiptap/style.css'

function App() {
  const [content, setContent] = useState('<p>Hello World!</p>')

  const handleImageUpload = async (file: File) => {
    // 实现你的图片上传逻辑
    const formData = new FormData()
    formData.append('file', file)
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    })
    const data = await response.json()
    return data.url
  }

  return (
    <TiptapEditor
      value={content}
      onChange={setContent}
      onImageUpload={handleImageUpload}
    />
  )
}

受控组件完整示例

import { useState } from 'react'
import { TiptapEditor } from 'zt-reactjs-tiptap'
import 'zt-reactjs-tiptap/style.css'

function EditorExample() {
  const [content, setContent] = useState('<p>开始编辑...</p>')

  const handleImageUpload = async (file: File): Promise<string> => {
    // 示例:上传到服务器
    const formData = new FormData()
    formData.append('image', file)
    
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    })
    
    const data = await response.json()
    return data.url
  }

  return (
    <div style={{ maxWidth: '800px', margin: '0 auto' }}>
      <h1>我的编辑器</h1>
      <TiptapEditor
        value={content}
        onChange={(html) => {
          setContent(html)
          console.log('内容已更新:', html)
        }}
        onImageUpload={handleImageUpload}
      />
      <div style={{ marginTop: '20px' }}>
        <h3>当前 HTML 内容:</h3>
        <pre style={{ background: '#f5f5f5', padding: '10px', overflow: 'auto' }}>
          {content}
        </pre>
      </div>
    </div>
  )
}

Props

| 属性 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | value | string | 否 | - | 编辑器的 HTML 内容 | | onChange | (html: string) => void | 否 | - | 内容变化时的回调函数,参数为 HTML 字符串 | | onImageUpload | (file: File) => Promise<string> | 否 | - | 图片上传处理函数,需返回图片 URL。若不提供,图片将以 Base64 格式插入 | | editorMode | 'notion-like' \| 'headless' | 否 | 'notion-like' | 编辑器模式:Notion 风格(斜杠命令、块状编辑等)或无头模式 | | headlessToolbarMode | 'always' \| 'on-focus' | 否 | 'always' | 仅在 editorMode='headless' 时生效always:工具栏始终显示;on-focus:编辑器聚焦或点击工具栏时显示,失焦到编辑器区域外时隐藏 | | commandMenuMaxHeight | number | 否 | 240 | 斜杠命令菜单最大高度(px) | | commandMenuMinHeight | number | 否 | 160 | 斜杠命令菜单最小高度(px) | | placeholder | string | 否 | "输入 '/' 查看命令..." | 编辑器为空时的占位文本 | | disabled | boolean | 否 | false | 是否禁用编辑器(只读) | | onChangeDebounceMs | number | 否 | 300 | onChange 防抖延迟(毫秒) | | border | boolean | 否 | true | 是否显示编辑器容器边框 | | imageMaxSizeBytes | number | 否 | 5242880(5MB) | 图片上传最大体积(字节),超过则拒绝并提示 | | formulaCategories | FormulaPickerCategory[] | 否 | 内置默认分类 | 公式选择器的分类列表。不传则使用内置分类;传入时可完全自定义或在默认基础上扩展(见下方「扩展公式分类」) | | maxHeight | number \| string | 否 | - | 编辑器容器的最大高度。不配置时容器为 height: 100%;配置后高度随内容从较小开始增长,达到该值后不再增高,超出部分在编辑区内滚动。数字表示像素(如 400),字符串为任意合法 CSS 长度(如 "50vh""20rem") |

限制编辑器最大高度(maxHeight)

不配置时编辑器容器占满父级高度(height: 100%)。传入 maxHeight 后,高度会随内容从较小开始增长,达到设定值后不再增高,超出部分在编辑区内滚动。

// 最大高度 400px,内容少时较矮,内容多到 400px 后内部滚动
<TiptapEditor value={content} onChange={setContent} maxHeight={400} />

// 使用 CSS 长度,如视口高度的一半
<TiptapEditor value={content} onChange={setContent} maxHeight="50vh" />

Headless 模式下的工具栏显示

editorMode="headless" 时,可以通过 headlessToolbarMode 控制顶部工具栏的显示策略:

  • headlessToolbarMode="always":工具栏始终显示。
  • headlessToolbarMode="on-focus":当编辑器获得焦点或用户点击工具栏区域时显示;当焦点离开整个编辑器容器(包括工具栏)后隐藏。点击工具栏按钮本身不会导致工具栏立即消失。

示例:

<TiptapEditor editorMode="headless" headlessToolbarMode="on-focus" />

功能说明

斜杠命令

在编辑器中输入 / 可以打开命令菜单,快速插入以下内容:

  • 标题:H1、H2、H3
  • 列表:有序列表、无序列表、任务列表
  • 引用块:带左边框的引用样式
  • 代码块:语法高亮的代码块
  • 表格:插入 3x3 表格
  • 图片:打开图片上传对话框
  • 数学公式:行内公式、块级公式
  • 分割线:水平分隔线

操作方式

  • 输入 / 打开命令菜单
  • 使用 ↑ ↓ 方向键选择
  • 按 Enter 确认插入
  • 按 Escape 关闭菜单

气泡菜单

选中文本时会显示浮动工具栏,包含以下功能:

  • 文本样式:粗体、斜体、下划线、删除线、行内代码
  • 颜色:文本颜色(10种预设 + 自定义)、背景高亮
  • 对齐:左对齐、居中、右对齐、两端对齐
  • 标题:快速切换 H1/H2/H3/正文
  • 上标/下标:数学公式常用
  • 清除格式:一键移除所有格式

表格操作

插入表格后,点击表格任意位置会显示表格工具栏,支持:

  • 在上方/下方插入行
  • 在左侧/右侧插入列
  • 删除当前行/列
  • 切换表头行
  • 删除整个表格

提示:鼠标悬停在表格上会显示操作按钮。

数学公式

基于 KaTeX 支持 LaTeX 格式的数学公式:

  • 行内公式:使用斜杠命令选择"行内公式",例如:E = mc^2
  • 块级公式:使用斜杠命令选择"块级公式",例如:
    \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
  • 编辑公式:点击已插入的公式可以打开编辑对话框修改
  • 实时预览:编辑时实时渲染公式效果

扩展公式分类:可通过 formulaCategories 自定义或扩展公式选择器中的分类与片段。库会导出 FORMULA_CATEGORIESFormulaPickerCategoryFormulaSnippetItem,便于在默认基础上追加分类:

import {
  TiptapEditor,
  FORMULA_CATEGORIES,
  type FormulaPickerCategory,
  type FormulaSnippetItem,
} from 'zt-reactjs-tiptap'
import 'zt-reactjs-tiptap/style.css'

const customCategory: FormulaPickerCategory = {
  id: 'custom',
  title: '自定义',
  items: [
    { id: 'my-1', label: '我的公式', latex: '\\mycommand{x}' },
  ] as FormulaSnippetItem[],
}

<TiptapEditor
  formulaCategories={[...FORMULA_CATEGORIES, customCategory]}
/>

HTML 转纯文本

库导出 htmlToPlainTextdomToPlainText,使用与编辑器相同的 schema 将 HTML 或 DOM 转为纯文本,结果与编辑器实例的 getText() 一致(如图片→[image]、公式→[latex]、表格→[table] 等)。

import { htmlToPlainText, domToPlainText } from 'zt-reactjs-tiptap'

// 从 HTML 字符串
const text = htmlToPlainText('<p>Hello</p><p>World</p>')
// => 'Hello\nWorld'

// 从 DOM 元素(如编辑器内容区)
const el = document.querySelector('.editor-content')
const text2 = domToPlainText(el)

// 单行模式(块之间用空格、换行替换为空格)
const oneLine = htmlToPlainText(html, { singleLine: true })

// 自定义块分隔符
const custom = htmlToPlainText(html, { blockSeparator: '\n\n' })

选项 HtmlToPlainTextOptions

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | blockSeparator | string | '\n' | 块级节点之间的分隔符;singleLine: true 时视为 ' ' | | singleLine | boolean | false | 为 true 时块之间用空格连接,结果中的换行会替换为空格 |

图片上传

支持两种方式插入图片:

  1. 文件上传:拖拽或选择本地图片文件
  2. URL 插入:通过图片链接地址插入

图片处理

  • 如果提供 onImageUpload 函数,图片将上传到服务器并返回 URL
  • 如果没有提供,图片将以 Base64 格式直接嵌入(适合小图片)
  • 支持 JPG、PNG、GIF 等常见格式
  • 建议图片大小不超过 5MB

任务列表

支持创建可交互的待办事项列表:

  • 使用斜杠命令插入"任务列表"
  • 点击复选框可切换完成状态
  • 支持嵌套任务(任务列表内再插入任务列表)

快捷键

| 快捷键 | 功能 | |--------|------| | Ctrl/Cmd + B | 粗体 | | Ctrl/Cmd + I | 斜体 | | Ctrl/Cmd + U | 下划线 | | Ctrl/Cmd + Z | 撤销 | | Ctrl/Cmd + Shift + Z | 重做 | | / | 打开斜杠命令菜单 | | Tab | 增加列表缩进 | | Shift + Tab | 减少列表缩进 |

依赖要求

  • React >= 18.0.0
  • React DOM >= 18.0.0

样式系统

样式导入

import 'zt-reactjs-tiptap/style.css'

样式文件包含:

  • ✅ Tailwind CSS v4 基础样式
  • ✅ shadcn/ui 主题变量
  • ✅ 编辑器组件样式
  • ✅ KaTeX 数学公式样式

文件大小:CSS 约 1.5MB(gzip 后约 950KB)

在其它项目中使用时样式不对?

  1. 务必导入样式:在使用编辑器的组件或入口文件顶部导入 import 'zt-reactjs-tiptap/style.css'

  2. 导入顺序:若希望用自己项目的主题覆盖编辑器主题,请先导入 zt-reactjs-tiptap/style.css,再导入你的全局样式

  3. CSS 变量覆盖:在你的全局样式中定义或覆盖 CSS 变量(如 --primary--background--border 等)

  4. 弹层/对话框:插入图片、公式等弹层通过 Portal 渲染到 document.body,库的样式为全局样式。若仍被覆盖,检查是否有全局 reset 或更高优先级的选择器影响弹层

开发

本项目使用 pnpm、React 19、Vite 7、TypeScript 5.9、Tailwind CSS v4、TipTap 3.x。

# 安装依赖
pnpm install

# 开发模式(启动示例应用)
pnpm dev

# 构建示例应用
pnpm build

# 构建库(用于发布到 npm)
pnpm build:lib

# 代码检查
pnpm lint

# 预览构建结果
pnpm preview

License

MIT