2024-05-26
Quillを利用してお手軽リッチエディターを実装する
リッチエディターの実装
新しいプロダクトを作る際ことになったら投稿機能を実装したいと思っている。
その際に以前から気になっていたQuillで実装してみたいと考えた。
また,3年前にGraphQL + Nextjs(Page router)で実装していたコードを見ていたところ,以下のようなライブラリを用いて実装していた。
"react-hook-form": "^7.7.1",
"react-markdown": "^6.0.2",
"remark-gfm": "^1.0.0"
参考資料
Quill 公式サイト
Quill テーマについて
https://quilljs.com/docs/customization/themes
概要
Quillはシンプルかつ強力なリッチテキストエディター。
基本的にスタイリングなどもインポートするだけで気軽に利用することができるためあまりセットアップに時間をかけずとも利用することが可能。
また,テーマも含めAPIも豊富に用意されておりカスタマイズもしやすい印象。
公式サイトからPlaygroundのように実際にどのようなコンポーネントが作成されるか確認できる。
環境構築
今回はvite + Reactの環境で試してみる。
適時Reactの環境でクライアントサイドを利用できる環境を構築していれば問題ない。
bun create vite@latest
ライブラリのインストール
bun install quill
エディターコンポーネントの作成
以下のような感じでRefとインスタンスを利用してコンポーネントを作成する。
今回のテーマはSnowを利用しているがBubbleを利用すればツールーバーがなくなり,クリックなどでスタイル変更できるといったより直感的なものとして利用できる。
この際にデフォルトで提供してくれているCSSをインポートすることを忘れずに。
QuillEditor.tsx
import Quill from "quill";
import "quill/dist/quill.snow.css";
import React, { useEffect, useRef } from "react";
interface QuillEditorProps {
value: string;
onChange: (content: string) => void;
}
const QuillEditor: React.FC<QuillEditorProps> = ({ value, onChange }) => {
const quillRef = useRef<HTMLDivElement | null>(null);
const quillInstance = useRef<Quill | null>(null);
useEffect(() => {
if (quillRef.current && !quillInstance.current) {
quillInstance.current = new Quill(quillRef.current, {
theme: "snow",
});
quillInstance.current.on("text-change", () => {
onChange(quillInstance.current!.root.innerHTML);
});
quillInstance.current.clipboard.dangerouslyPasteHTML(value);
}
}, [value, onChange]);
return <div ref={quillRef} />;
};
export default QuillEditor;
インポートとコンテンツの表示
エディターのインポートを行いつつStateを利用してコンテンツを表示していく。
DBなどを用意すればDraft機能なども実装できると思った。
App.tsx
import React, { useState } from "react";
import QuillEditor from "./QuillEditor";
const App: React.FC = () => {
const [editorContent, setEditorContent] = useState<string>("");
return (
<>
<h1>Quill Editor Example</h1>
<QuillEditor value={editorContent} onChange={setEditorContent} />
<div>
<h2>Editor Content</h2>
<div dangerouslySetInnerHTML={{ __html: editorContent }} />
</div>
</>
);
};
export default App;
その後にDevを起動させる
bun run dev
するといい感じのUIのコンポーネントが作成されていることを確認することができる。
また,ここでスタイリングされたものはクラスなどでスタイルが変化しているのではなくタグを用いたものになっているのでカスタムCSSファイルを適用すれば利用したいデザインのコンテンツを作成することが可能になる。
カスタムCSSの適用
カスタムCSSのファイルを作成する。
syles/custom-editor.css
.custom-preview h1 {
font-size: 2.5em;
color: #ff4081;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
border-bottom: 2px solid #ff4081;
padding-bottom: 10px;
margin-bottom: 20px;
}
.custom-preview h2 {
font-size: 2em;
color: #3f51b5;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
border-bottom: 1px solid #3f51b5;
padding-bottom: 8px;
margin-bottom: 18px;
}
.custom-preview em {
}
.custom-preview strong {
}
.custom-preview a {
}
....
カスタムスタイリングを利用できるようにクラス名とインポートを追加する。
このコンポーネントを切り出してインポートすることも可能。
App.tsx
import React, { useState } from "react";
import QuillEditor from "./QuillEditor";
import "./styles/custom-editor.css";
const App: React.FC = () => {
const [editorContent, setEditorContent] = useState<string>("");
return (
<>
<h1>Quill Editor Example</h1>
<QuillEditor value={editorContent} onChange={setEditorContent} />
<h2>Editor Content</h2>
<div className="custom-preview">
<div dangerouslySetInnerHTML={{ __html: editorContent }} />
</div>
</>
);
};
export default App;
再度確認するとこのようになっている。
まとめ
非常に強力で導入しやすいコンポーネントライブラリであると思った。
またツールバーの編集やシンタックスハイライトも可能なため利用できる範囲が非常に広いように感じた。
個人的にはもし利用することになったらSnowとBubbleの両方をトグルボタンなどで切り替えて利用できるように実装してみたい。
ぜひ過去の自分で教えてあげたい。