Has anyone built a Table of Content plugin before with PlateJs? #2592
-
I want to build a Table of Content Area Beside my editor. I think I should make a plugin with Considering TOC component will reside outside the editor I am not sure what should be the best approach? (Syncing state will get slow I can assume one there are a lot of content in the editor) |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 5 replies
-
This could be a plugin, while the UI part is outside Plate. Instead of updating the ToC on each change, you could override the relevant editor methods. |
Beta Was this translation helpful? Give feedback.
-
I would suggest using the same pattern we usually use for toolbars. Toolbars are very similar to a ToC, since they, too, depend on the state of the editor to show which formatting options are enabled for the current selection. The recommended solution for toolbars is to wrap both the Plate editor and the toolbar in a PlateProvider. From anywhere inside the PlateProvider, you can call The performance issue isn't really an issue unless your ToC component takes a particularly long time to render. If that's the case, you could throttle the computation so it runs at most once every 100ms and cache the output (the list of headings) in a state variable. As always, don't prematurely optimise. |
Beta Was this translation helpful? Give feedback.
-
I am pasting what I did here in case someone searches for this in future. I used const TableOfContent = () => {
const editor = usePlateEditorState<MyValue>();
return (
<div className="fixed left-3 top-12 p-6 rounded-md">
{editor.children.map((el, i) => {
if (el.type === "h1") {
return (
<p key={i}>
<a href={`#${el.id}`} className="text-lg">
{el.children?.[0].text as string}
</a>
</p>
);
} else if (el.type === "h2") {
return (
<p key={i}>
<a href={`#${el.id}`} className="text-lg ml-6">
{el.children?.[0].text as string}
</a>
</p>
);
} else if (el.type === "h3") {
return (
<p key={i}>
<a href={`#${el.id}`} className="text-lg ml-12">
{el.children?.[0].text as string}
</a>
</p>
);
} else return null;
})}
</div>
);
}; Then I just used this component inside |
Beta Was this translation helpful? Give feedback.
I would suggest using the same pattern we usually use for toolbars. Toolbars are very similar to a ToC, since they, too, depend on the state of the editor to show which formatting options are enabled for the current selection.
The recommended solution for toolbars is to wrap both the Plate editor and the toolbar in a PlateProvider. From anywhere inside the PlateProvider, you can call
usePlateEditorState
to get aneditor
value that will update on every change.The performance issue isn't really an issue unless your ToC component takes a particularly long time to render. If that's the case, you could throttle the computation so it runs at most once every 100ms and cache the output (the list…