メインコンテンツまでスキップ

BlockNoteでNotionライクなテキストエディタを実装する

· 約9分
森田 有貴

森田です。

現在開発しているプロダクトで BlockNote というリッチテキストエディタを使う機会があったのですが、これがめちゃめちゃ便利だったので今回はその紹介をしたいと思います!

BlockNote とは?

BlockNote は React で Notion のようなブロックベースのテキストエディタを実装できるライブラリです。デフォルトの状態で Notion に引けを取らない UX が設定されており、とても簡単に高クオリティなテキストエディタを実装できます。

https://www.blocknotejs.org/

実装

長々と説明するより実際に見てもらうほうが早いと思うので、早速で実装してみましょう! 今回もNextjsで行きます

サクッとプロジェクトを作成して...

$ npx create-next-app blocknote-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes

必要なライブラリをインポート

npm install @blocknote/core @blocknote/react @blocknote/mantine

エディタ用のコンポーネントを作成して...

/src/app/page.tsx
"use client";

import "@blocknote/core/fonts/inter.css";
import { useCreateBlockNote } from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";

export const Editor = () => {
const editor = useCreateBlockNote();
return (
<div>
<BlockNoteView editor={editor} />
</div>
);
};

ページに表示するだけ!

/src/app/page.tsx
import { Editor } from "./components/Editor";

const Page = () => {
return (
<>
<Editor />
</>
);
};

export default Page;

これだけで実装完了!

video

とっても簡単にNotionのようなテキストエディタを実装できてしまいました🎉🎉🎉

できること

blocknoteでは文字を入力できるのはもちろん、文字のサイズや色の変更、画像や動画などさまざまなコンテンツを入力表示させることができます。

image1

image2

入力欄の左の+をクリックすると入力できるものリストが表示されます。

基本的にはMarkdown記法と同様に#でHeadingにしたり、 - でリスト表示にしたりという感じで入力できます。また、+の横の点々の部分をクリックすると文字の色や背景色なども選ぶことができます。

画像や動画などはurlを入力することによって表示させることができます。

さらにBlockNoteという名前の通り、入力したコンテンツをブロックとして移動させることも簡単にできてしまいます。

video2

ものすごい機能が充実していますね😲

スタイル変更

スタイルもかなり自由に変更できるようになっています。 いくつか抜粋してご紹介します。

文字サイズ変更

初期設定では文字のサイズが大きすぎるので変更してみましょう。

.editor-custom-style .bn-editor h1 {
font-size: 18px;
}

.editor-custom-style .bn-editor h2 {
font-size: 16px;
}

.editor-custom-style .bn-editor h3 {
font-size: 14px;
}

.editor-custom-style .bn-editor {
font-size: 14px;
}

cssインポートしてクラスを指定すると...

import "./editor.css";

export const Editor = () => {
const editor = useCreateBlockNote();

return (
<div>
<BlockNoteView editor={editor} className="editor-custom-style" />
</div>
);
};

image3

いい感じのサイズに変更できました!

文字サイズ以外にも色々カスタマイズができるようになっています。

テーマ

続いてテーマを編集してましょう! 背景色を赤色にしてみます。

import { BlockNoteView, darkDefaultTheme } from "@blocknote/mantine";
import { Theme } from "@blocknote/mantine";

export const Editor = () => {
const editor = useCreateBlockNote();

const lightRedTheme = {
colors: {
editor: {
background: "red",
},
},
} satisfies Theme;

const redTheme = {
light: lightRedTheme,
dark: darkDefaultTheme,
};

return (
<div>
<BlockNoteView editor={editor} className="editor-custom-style" theme={redTheme} />
</div>
);
};

image4

むちゃくちゃ目に悪そうですね。

みてわかる通りライトテーマとダークテーマそれぞれ設定できるようになっています。 今回はライトテーマのみにカスタムテーマを当てています。

こちらもかなり自由度高くカスタマイズできるようになっています。

詳しくはこちら↓

https://www.blocknotejs.org/docs/styling-theming/themes

言語変更

デフォルトではプレイスホルダーやメニューの部分の言語が英語になっています。 日本語の設定が用意されているので変更してみましょう。

import { locales } from "@blocknote/core";

export const Editor = () => {
const editor = useCreateBlockNote({
dictionary: locales.ja,
});

return (
<div>
<BlockNoteView editor={editor} className="editor-custom-style" />
</div>
);
};

localesをインポートしてlocales.jaを設定するだけ。

image5

特に変な日本語になっている部分もないですね。

おまけ

入力した内容を取得する

textareaタグのonChange={(e) => console.log(e.target.value)}的なことをしてみましょう!

Reactのテキストエディタですからね。内容が取得できてなんぼですからね。

入力された内容はeditor.documentで取得ができます。また、inputやtextareaと同様にonChangeで入力内容の変化を感知できます。

export const Editor = () => {
const editor = useCreateBlockNote();

const onChange = () => {
console.log(editor.document);
};

return (
<div>
<BlockNoteView editor={editor} onChange={onChange} />
</div>
);
};

video3

というわけで入力が取得できました。

ただ、みてわかる通りこの実装方法ではBlockNote特有のBlock型で出力されてしまいます。

なのでマークダウンに変換して出力してみましょう!

blocksToMarkdownLossyを使ってonChangeを以下のように変更します

const onChange = async () => {
const markdown = await editor.blocksToMarkdownLossy(editor.document);
console.log(markdown);
};

video4

マークダウンで出力されるようになりました!

プログラム側から入力する

続いてプログラム側から内容を入力する方法をご紹介します。

こちらはinputやtextareaとは全く異なります。

export const Editor = () => {
const editor = useCreateBlockNote();

const markdown = `# Hello, world!`;

const loadMarkdown = async () => {
const blocks = await editor.tryParseMarkdownToBlocks(markdown);
editor.replaceBlocks(editor.document, blocks);
};

return (
<div>
<BlockNoteView editor={editor} />
<button onClick={() => loadMarkdown()}>読み込む</button>
</div>
);
};

loadMarkdown関数で入力するマークダウンの文字列をBlock型に変換し、editor.replaceBlocksで置き換えているという感じです。 

実際に動かしてみるとこんな感じ。

video5

replace以外にinsertなどさまざまな操作が可能になっています。

詳しくはこちら↓

https://www.blocknotejs.org/docs/editor-api/manipulating-blocks

おわり

今回はBlockNoteをご紹介しました。今回紹介できたのはほんの一部で他にも便利な機能が沢山用意されているので、ぜひ実際に使っていただければと思います!

公式のDiscordサーバーも活発に動いており、日々質問や不具合報告など飛び交っています。わからないことがあればこちらで聞くといいかもしれないですね。

機会があれば実際にBlockNoteを用いた機能開発も紹介したいと思っています!

ではまた。