はじめに
「Notionのようなリッチテキストエディタを自分のアプリにも組み込みたいけれど、既存のWYSIWYGライブラリはカスタマイズの自由度が低くて痛い目を見た」——そんな経験はないでしょうか。太字や箇条書きだけなら簡単でも、独自のブロック要素やメンション機能、コメント挿入のような少し凝った機能を足そうとした途端、ライブラリの制約に阻まれることは珍しくありません。
Slateは、このような「痒い所に手が届かない」問題を根本から解決するために設計された、フレームワークにとらわれないリッチテキストエディタのビルドツールキットです。エディタそのものを完成品として提供するのではなく、エディタを組み立てるための部品を提供するというアプローチによって、必要な機能を必要な形で実装できる自由度の高さが最大の魅力です。
Slateとは
Slateは、Reactをベースに完全にカスタマイズ可能なリッチテキストエディタを構築できるオープンソースのライブラリです。Draft.jsやQuillといった他の有名なエディタライブラリとは異なり、「あらかじめ用意されたエディタ」ではなく「エディタを作るためのフレームワーク」として設計されている点が大きな特徴です。
ドキュメントの内容はプレーンなJSONのデータ構造として表現され、そのデータをどう画面に描画し、どう編集操作を扱うかはすべてプラグインという仕組みで拡張していきます。この設計により、Medium風の記事エディタからSlack風のチャット入力欄まで、幅広い用途に対応できます。
主な特徴
- 完全なカスタマイズ性 - ノードのレンダリング方法や編集時の振る舞いをプラグインで自在に上書きでき、独自のブロックやインライン要素を無理なく組み込めます
- プラグインによる関心の分離 - 太字、リンク、画像埋め込みといった機能ごとにロジックを分割でき、必要な機能だけを組み合わせて使えます
- JSONベースのドキュメントモデル - コンテンツがシリアライズしやすいプレーンオブジェクトで表現されるため、サーバーへの保存やHTML変換などの後処理がしやすくなっています
- React/TypeScriptとの親和性 - Reactのコンポーネントモデルに沿った実装のため、既存のReactアプリに自然に組み込めます
インストール
Slateはコアロジックを担うslateと、React向けのバインディングであるslate-reactの2つのパッケージで構成されています。
# npm
npm install slate slate-react
# yarn
yarn add slate slate-react
# pnpm
pnpm add slate slate-react
TypeScriptを使う場合は、カスタム要素の型を拡張するための型定義も一緒に用意しておくと後々の開発がスムーズになります。
基本的な使い方
まずは最小構成のエディタを作ってみます。SlateではSlateコンポーネントがエディタの状態(値)を管理し、Editableコンポーネントが実際に編集可能な画面を描画します。
import { useState, useMemo } from "react";
import { createEditor } from "slate";
import { Slate, Editable, withReact } from "slate-react";
const initialValue = [
{
type: "paragraph",
children: [{ text: "ここに文章を入力できます。" }],
},
];
function SimpleEditor() {
const editor = useMemo(() => withReact(createEditor()), []);
const [value, setValue] = useState(initialValue);
return (
<Slate editor={editor} initialValue={value} onChange={setValue}>
<Editable placeholder="本文を入力してください..." />
</Slate>
);
}
export default SimpleEditor;
createEditor()でエディタのコアインスタンスを作成し、withReactでReact用の機能(DOM連携やイベント処理など)を追加しています。valueはドキュメントの中身を表すJSON配列で、onChangeによって編集のたびに更新されます。
次に、太字のようなテキスト装飾を反映させてみましょう。Slateではテキストの見た目を変えるためのrenderLeafというレンダリング関数を使います。
import { useCallback } from "react";
function Leaf({ attributes, children, leaf }) {
if (leaf.bold) {
children = <strong>{children}</strong>;
}
return <span {...attributes}>{children}</span>;
}
function FormattedEditor() {
const editor = useMemo(() => withReact(createEditor()), []);
const [value, setValue] = useState(initialValue);
const renderLeaf = useCallback((props) => <Leaf {...props} />, []);
return (
<Slate editor={editor} initialValue={value} onChange={setValue}>
<Editable renderLeaf={renderLeaf} placeholder="本文を入力してください..." />
</Slate>
);
}
このように、装飾の判定と描画をコンポーネントとして切り出せるため、太字以外にも斜体や下線、ハイライトなど好きなだけ装飾を追加していけます。
実践的なユースケース
実際のアプリケーションでは、キーボードショートカットで太字のオン・オフを切り替える場面が多くあります。onKeyDownイベントとSlateのコマンドAPIを組み合わせることで実現できます。
import { Editor, Transforms } from "slate";
const toggleBold = (editor) => {
const isActive = Editor.marks(editor)?.bold === true;
if (isActive) {
Editor.removeMark(editor, "bold");
} else {
Editor.addMark(editor, "bold", true);
}
};
function EditorWithShortcuts() {
const editor = useMemo(() => withReact(createEditor()), []);
const [value, setValue] = useState(initialValue);
const renderLeaf = useCallback((props) => <Leaf {...props} />, []);
const handleKeyDown = (event) => {
if (event.ctrlKey && event.key === "b") {
event.preventDefault();
toggleBold(editor);
}
};
return (
<Slate editor={editor} initialValue={value} onChange={setValue}>
<Editable
renderLeaf={renderLeaf}
onKeyDown={handleKeyDown}
placeholder="Ctrl+Bで太字を切り替えられます"
/>
</Slate>
);
}
Editor.marksで現在のカーソル位置の装飾状態を取得し、Editor.addMark・Editor.removeMarkで装飾のオン・オフを切り替えています。同様の仕組みで見出しや箇条書きへの変換ボタンも実装でき、社内向けのドキュメント作成ツールやコメント機能付きのレビューツールなど、要件が細かく異なるプロダクトに合わせて機能を積み上げていけます。
また、ドキュメントの内容はプレーンなJSON構造そのものなので、サーバーに保存する際も特別なシリアライズ処理を挟まずにそのまま送信でき、HTML変換用のライブラリと組み合わせればブログ記事のような公開用コンテンツの生成にも応用できます。
まとめ
Slateは、完成されたエディタを使うのではなく「自分たちの要件に合わせてエディタを組み立てる」という発想に立ったリッチテキストエディタのフレームワークです。createEditorとwithReactでコアを用意し、renderLeafやrenderElementで見た目を、EditorやTransformsのAPIで編集操作をそれぞれ組み立てていくことで、他のライブラリでは実現しづらい独自の編集体験を作り上げられます。
学習コストはやや高めですが、その分だけ「あの機能が実装できない」という壁にぶつかりにくいのがSlateの強みです。柔軟性の高いエディタが必要になったときは、ぜひ選択肢の一つに加えてみてください。
