I'm using React, Next.js, and TipTap as part of a project. I have been using TipTap with useEditor
initially, but to allow more flexibility and prevent the need to pass the editor to every child component in the editor, I have been refactoring to use <EditorProvider />
instead.
When using <EditorProvider>
, the code seems to ignore <EditorContent>
and place content at the top of the <EditorProvider />
children.
I have separated the Editor into its own reusable component <BlockEditor>
that can be nested inside a <EditorProvider />
BlockEditor.js
const BlockEditor = () => {
const { editor } = useCurrentEditor();
return (
<>
<FloatingMenu editor={null}>
<BlockMenu />
</FloatingMenu>
<BubbleMenu editor={null} className="flex space-x-2">
<TextMenu />
<ImageMenu />
<GalleryMenu />
</BubbleMenu>
<EditorContent editor={editor} />
</>
);
};
Then I use the<BlockEditor>
inside a page or other client component, where I want to control the layout so that other components on the page can access the editor via const { editor } = useCurrentEditor();
ExampleEditor.js
export default function ExampleEditor() {
// define your extension array
const extensions = [
StarterKit
];
const content = `
<h1>
This is a test,
</h1>
`;
return (
<EditorProvider
extensions={extensions}
content={content}
>
<div className="w-full flex-1 flex overflow-hidden">
{/* Editor */}
<div className="h-full flex flex-col min-h-200 flex-grow overflow-hidden">
<div className="w-full p-4 overflow-hidden h-full">
<BlockEditor />
</div>
</div>
{/* Settings aside */}
<div className="h-full w-[350px] border-l border-neutral-200 bg-gray-50">
<TextInspector />
<ImageInspector />
<GalleryInspector />
</div>
</div>
</EditorProvider>
);
}
In this example <TextInspector />
, <ImageInspector />
, <GalleryInspector />
are all using useCurrentEditor();
to get access to the editor and provide some edit utility to the active element.
The issue is that the EditorProvider seems to render the content at the top of its children and not where the BlockEditor.js <EditorContent>
is. This wasn't an issue when using useEditor
, but it seems to be now.
There isn't much documentation on <EditorProvider>
, so I'm not sure if it supports <EditorContent>
or not, and how I should be using it correctly. If there are any examples of how I should be using and nesting < EditorProvider>
and <EditorContent>
, it would be a big help.
Note: The other odd thing I've noticed is that occasionally, when running the Next.js app in dev mode and updating the code, it renders correctly for a second, before reverting back to placing the content at the top of the Provider children. I thought this might indicate some server-side rendering issue; however, all Editor components are using "use client"
.
Diving into the code in node_modules
for EditorProvider
, this is how it is defined:
export function EditorProvider({
children, slotAfter, slotBefore, editorContainerProps = {}, ...editorOptions
}: EditorProviderProps) {
const editor = useEditor(editorOptions)
if (!editor) {
return null
}
return (
<EditorContext.Provider value={{ editor }}>
{slotBefore}
<EditorConsumer>
{({ editor: currentEditor }) => (
<EditorContent editor={currentEditor} {...editorContainerProps} />
)}
</EditorConsumer>
{children}
{slotAfter}
</EditorContext.Provider>
)
}
You can use editorContainerProps
to set the EditorContent
related props. You do not need to use EditorContent
separately.
<EditorProvider
extensions={extensions}
content={content}
editorContainerProps={/* any EditorContent prop you want to set */}
>
{/* Editor code */}
</EditorProvider>```
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With