Overview
The Yoopta Editor is the main component that orchestrates all plugins, marks, and UI components. You create an editor instance with createYooptaEditor() (passing plugins and optional marks/value there), then render <YooptaEditor editor={editor} onChange={...} />. Content is stored on the editor instance and synced via onChange.
Creating an Editor Instance
Use createYooptaEditor() with an options object. Plugins are required; marks and initial value are optional:
import { createYooptaEditor } from '@yoopta/editor';
import { ParagraphPlugin } from '@yoopta/paragraph';
const editor = useMemo(
() =>
createYooptaEditor({
plugins: [ParagraphPlugin],
marks: [], // optional, e.g. from @yoopta/marks
value: undefined, // optional initial content
id: undefined, // optional editor ID
readOnly: false,
}),
[],
);
Always wrap createYooptaEditor() in useMemo (with stable plugins/marks) to prevent recreating the editor on every render.
Plugins and marks are configured at creation time, not on the <YooptaEditor> component. Value is managed via the editor instance and onChange.
YooptaEditor Component Props
The <YooptaEditor> component accepts:
Required
The editor instance from createYooptaEditor()
Optional
onChange
(value: YooptaContentValue, options: YooptaOnChangeOptions) => void
Called when content changes. Use it to sync value to your state (e.g. for saving or controlled usage).
onPathChange
(path: YooptaPath) => void
Called when the selection path changes (current block, selected blocks, etc.).
Whether to focus the editor on mount.
Placeholder text when the editor is empty.
CSS class for the editor wrapper.
Inline styles for the editor wrapper.
UI components to render inside the editor (e.g. toolbar, slash menu, block actions).
renderBlock
(props: RenderBlockProps) => ReactNode
Custom wrapper for each block (e.g. for drag-and-drop).
Basic Example
import { useMemo, useState } from 'react';
import { YooptaEditor, createYooptaEditor } from '@yoopta/editor';
import { ParagraphPlugin } from '@yoopta/paragraph';
const plugins = [ParagraphPlugin];
export default function MyEditor() {
const editor = useMemo(
() =>
createYooptaEditor({
plugins,
value: undefined,
}),
[],
);
const [value, setValue] = useState(editor.children);
const handleChange = (newValue, options) => {
setValue(newValue);
console.log('Operations:', options.operations);
};
return (
<YooptaEditor
editor={editor}
onChange={handleChange}
placeholder="Start typing..."
autoFocus
/>
);
}
Content Value Structure
Content is a record of block ID → block data. Type names use PascalCase for block types (e.g. Paragraph), and kebab-case for element types inside value.
type YooptaContentValue = Record<string, YooptaBlockData>;
type YooptaBlockData = {
id: string;
type: string; // e.g. 'Paragraph', 'HeadingOne'
meta: {
order: number;
depth: number;
align?: 'left' | 'center' | 'right';
};
value: SlateElement[]; // Slate nodes (paragraph, heading-one, etc.)
};
Example
{
"block-1": {
"id": "block-1",
"type": "Paragraph",
"meta": { "order": 0, "depth": 0 },
"value": [
{
"id": "el-1",
"type": "paragraph",
"children": [{ "text": "Hello World!" }]
}
]
}
}
onChange Options
The onChange callback receives the new content and an options object:
type YooptaOnChangeOptions = {
operations: YooptaOperation[]; // List of operations that caused the change
};
Use options.operations to know what changed (insert, update, delete, move, etc.) without diffing the whole value.
Styling the Editor
Using className
<YooptaEditor editor={editor} onChange={onChange} className="my-editor" />
.my-editor {
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
min-height: 500px;
}
Using style
<YooptaEditor
editor={editor}
onChange={onChange}
style={{
maxWidth: '800px',
margin: '0 auto',
padding: '40px 20px',
minHeight: '500px',
}}
/>
Multiple Editors
Each editor instance is independent. Create separate instances with createYooptaEditor() and separate state for each:
function MultipleEditors() {
const editor1 = useMemo(() => createYooptaEditor({ plugins }), []);
const editor2 = useMemo(() => createYooptaEditor({ plugins }), []);
const [value1, setValue1] = useState(editor1.children);
const [value2, setValue2] = useState(editor2.children);
return (
<>
<YooptaEditor editor={editor1} onChange={setValue1} />
<YooptaEditor editor={editor2} onChange={setValue2} />
</>
);
}
Next Steps