はじめに
Webアプリにリッチテキストエディタを組み込みたい。でも、世の中のWYSIWYGエディタは見た目が固定されていて、カスタマイズしようとすると地獄を見る。かといってProseMirrorを直接触るのは学習コストが高すぎる。
Tiptapは、そんな悩みを解決してくれるヘッドレス型のリッチテキストエディタフレームワークです。GitHubで33,900スター以上、月間1,280万ダウンロードという実績を持っています。
正直なところ、最初は「またエディタライブラリか」くらいに思っていました。でも触ってみたら、ProseMirrorの強力な機能を維持しながら、開発者体験を大幅に改善している。30代になって思うのは、良いツールは時間という最大のリソースを節約してくれるということですね。
Tiptapとは
TiptapはProseMirrorをベースにした「ヘッドレス」なリッチテキストエディタフレームワークです。「ヘッドレス」というのは、UIが含まれていないという意味。見た目は完全に自分で決められる。
ドイツのueberdosis社が開発・メンテナンスしており、MITライセンスのオープンソースです。LinkedInやGitLab、Substackといった大手企業でも採用されています。
現在のバージョンは3.12.1。React、Vue、Svelte、プレーンJavaScriptなど、主要なフレームワークに対応しています。
特徴・メリット
1. ヘッドレス設計による完全なデザイン自由度
UIが含まれていないため、TailwindでもBootstrapでも、好きなCSSフレームワークでスタイリングできます。
個人的には、この「見た目に縛られない」というのが一番の魅力。既存のデザインシステムに組み込むとき、エディタだけ浮いてしまうというのはよくある話。Tiptapならそれがない。
2. 100以上の拡張機能
- ノード: 見出し、段落、画像、テーブル、コードブロック
- マーク: 太字、イタリック、リンク、ハイライト
- 機能拡張: ドラッグ&ドロップ、プレースホルダー、履歴
必要な機能だけを選んで組み合わせられる。これ、意外と重要なポイントで、バンドルサイズを最小限に抑えられます。
3. フレームワーク非依存
React、Vue 2/3、Svelte、Next.js、Nuxt、Alpine.js、プレーンJavaScript。主要なフレームワークほぼ全てに対応しています。
チームが別のフレームワークに移行しても、Tiptapの知識は活きる。コスパ的に考えても、学習投資として悪くない選択です。
4. TypeScriptフレンドリー
型定義がしっかりしているので、エディタの補完が効く。拡張機能を作るときも型安全に開発できます。
5. Pro機能も充実
オープンソース版に加えて、以下のPro機能も提供されています:
- リアルタイム共同編集: Google Docsのような複数人同時編集
- コメント機能: インラインコメントとスレッド
- AI機能: 文法修正、翻訳、要約などのAIコマンド
- ドキュメント変換: DOCX/Markdownのインポート・エクスポート
ビジネス用途で本格的に使うなら、Pro版を検討する価値があります。
インストール方法
Reactの場合
npm install @tiptap/react @tiptap/pm @tiptap/starter-kit
必要なパッケージは3つ:
- @tiptap/react: React向けのバインディング
- @tiptap/pm: ProseMirrorライブラリ(エディタの基盤)
- @tiptap/starter-kit: よく使う拡張機能のセット
Vueの場合
npm install @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit
Vue 2を使っている場合は@tiptap/vue-2を使用します。
プレーンJavaScriptの場合
npm install @tiptap/core @tiptap/pm @tiptap/starter-kit
基本的な使い方
Reactでの最小構成
// src/Tiptap.tsx
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
const Tiptap = () => {
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello World!</p>',
})
return <EditorContent editor={editor} />
}
export default Tiptap
これだけで動く。見出し、箇条書き、太字、イタリック、コードブロックが使えるエディタが完成します。
ツールバーの追加
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
const Tiptap = () => {
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello World!</p>',
})
if (!editor) {
return null
}
return (
<div>
<div className="toolbar">
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className={editor.isActive('bold') ? 'is-active' : ''}
>
太字
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
className={editor.isActive('italic') ? 'is-active' : ''}
>
斜体
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
>
見出し2
</button>
</div>
<EditorContent editor={editor} />
</div>
)
}
editor.chain().focus().toggleBold().run()という書き方がTiptapの特徴。メソッドチェーンで複数の操作を連続実行できます。
FloatingMenuとBubbleMenu
import { useEditor, EditorContent } from '@tiptap/react'
import { FloatingMenu, BubbleMenu } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
const Tiptap = () => {
const editor = useEditor({
extensions: [StarterKit],
content: '<p>テキストを選択してみてください</p>',
})
return (
<>
<EditorContent editor={editor} />
{editor && (
<>
<FloatingMenu editor={editor}>
<button onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}>
H1
</button>
<button onClick={() => editor.chain().focus().toggleBulletList().run()}>
箇条書き
</button>
</FloatingMenu>
<BubbleMenu editor={editor}>
<button onClick={() => editor.chain().focus().toggleBold().run()}>
太字
</button>
<button onClick={() => editor.chain().focus().toggleLink({ href: 'https://example.com' }).run()}>
リンク
</button>
</BubbleMenu>
</>
)}
</>
)
}
FloatingMenuは空行にカーソルがあるときに表示され、BubbleMenuはテキストを選択したときに表示される。Notionライクな操作感を簡単に実現できます。
SSR対応(Next.js)
サーバーサイドレンダリング環境では、クライアントサイドでのみ初期化する必要があります。
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello World!</p>',
immediatelyRender: false, // SSR時はfalse
})
これを忘れるとハイドレーションエラーが出るので注意。
実践的なユースケース
Notion風ブロックエディタ
スラッシュコマンドでブロックタイプを切り替える、Notionライクなエディタ。
import { Extension } from '@tiptap/core'
import Suggestion from '@tiptap/suggestion'
const SlashCommands = Extension.create({
name: 'slashCommands',
addOptions() {
return {
suggestion: {
char: '/',
items: ({ query }) => {
return [
{ title: '見出し1', command: ({ editor }) => editor.chain().focus().toggleHeading({ level: 1 }).run() },
{ title: '箇条書き', command: ({ editor }) => editor.chain().focus().toggleBulletList().run() },
{ title: 'コードブロック', command: ({ editor }) => editor.chain().focus().toggleCodeBlock().run() },
].filter(item => item.title.toLowerCase().includes(query.toLowerCase()))
},
},
}
},
addProseMirrorPlugins() {
return [
Suggestion({
editor: this.editor,
...this.options.suggestion,
}),
]
},
})
CMSのリッチテキストエディタ
ブログやドキュメント管理システムの編集画面として。HTMLまたはJSONで出力できるので、データベースへの保存も柔軟に対応できます。
// HTMLで取得
const html = editor.getHTML()
// JSONで取得
const json = editor.getJSON()
// Markdownで取得(拡張機能追加が必要)
// npm install @tiptap/extension-markdown
社内ドキュメントツール
テーブル、画像、コードブロックを組み合わせた技術ドキュメント用エディタ。
npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-cell @tiptap/extension-table-header @tiptap/extension-image @tiptap/extension-code-block-lowlight
メール作成フォーム
リンク、画像、書式設定ができるメール本文エディタとして。
拡張機能の追加
StarterKit以外の機能を追加する例:
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Placeholder from '@tiptap/extension-placeholder'
import Link from '@tiptap/extension-link'
import Image from '@tiptap/extension-image'
import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
const editor = useEditor({
extensions: [
StarterKit,
Placeholder.configure({
placeholder: 'ここに入力...',
}),
Link.configure({
openOnClick: false,
}),
Image,
TaskList,
TaskItem.configure({
nested: true,
}),
],
content: '',
})
必要な機能だけ追加できるので、バンドルサイズの無駄がない。
注意点
学習曲線
Tiptap自体は使いやすいですが、高度なカスタマイズをしようとするとProseMirrorの知識が必要になることがあります。ただ、Tiptapのドキュメントは充実しているので、基本的な使い方で困ることは少ないです。
スタイリングは自分で
ヘッドレスなので、見た目は全て自分でCSSを書く必要があります。これをメリットと捉えるかデメリットと捉えるかは、プロジェクト次第。
Pro機能は有料
共同編集やAI機能を使いたい場合は、Pro版のライセンスが必要です。個人開発なら無料版で十分ですが、チーム開発で共同編集が必要なら検討の余地あり。
まとめ
Tiptapを使ってみて感じたこと:
- 学習コスト: 基本は1日で把握できる。ProseMirrorより圧倒的に楽
- カスタマイズ性: ヘッドレスなので見た目は完全自由
- 拡張性: 100以上の公式拡張 + カスタム拡張も作れる
- フレームワーク対応: React/Vue/Svelteなど、主要なものは全部OK
- パフォーマンス: ProseMirrorベースなので大きな文書でも安定
正直なところ、リッチテキストエディタを1から実装するのは相当な工数がかかります。選択範囲の管理、履歴管理、クリップボード対応...考えるだけで気が遠くなる。それがTiptapなら、数時間で本格的なエディタが作れる。
CMSの管理画面、社内ツール、ノーコードサービスの編集機能。リッチテキストエディタが必要なプロジェクトなら、Tiptap一択ですね。
まだ触ったことがない人は、公式サイトのPlaygroundから試してみてください。どれだけ簡単に動くか、実感できると思います。
