Overview
The YooptaEditor component is the main React component for rendering the editor. It manages the editor state, handles changes, and provides a container for toolbar and menu components.
Component Signature
function YooptaEditor ( props : YooptaEditorProps ) : JSX . Element
Props
The editor instance created with createYooptaEditor(). This instance manages all editor state and operations. const editor = useMemo (() => createYooptaEditor ({ plugins , marks }), []);
onChange
(value: YooptaContentValue, options: YooptaOnChangeOptions) => void
Callback fired when editor content changes. Receives the new content value and metadata about the change. The complete updated editor content as a Record of block IDs to block data.
Metadata about the change Array of operations that caused the change. Filtered to exclude internal operations like validation and slate updates. Operation types include: insert_block, delete_block, update_block, move_block, set_block_meta, set_block_value, etc.
< YooptaEditor
editor = { editor }
onChange = {( value , { operations }) => {
console . log ( 'Content changed:' , value );
console . log ( 'Operations:' , operations );
saveToDatabase ( value );
}}
/>
onPathChange
(path: YooptaPath) => void
Callback fired when the current block path (cursor position) changes. Show YooptaPath properties
The order index of the currently focused block, or null if no block is focused.
Array of block order indices that are currently selected (for multi-block selection).
Browser Selection object representing the current text selection.
source
'selection-box' | 'native-selection' | 'mousemove' | 'keyboard' | 'copy-paste' | null
The source/trigger of the path change.
Whether to automatically focus the editor on mount. < YooptaEditor editor = { editor } autoFocus />
Placeholder text to show when the editor is empty. < YooptaEditor
editor = { editor }
placeholder = "Type / to open command menu..."
/>
CSS class name to apply to the editor container. < YooptaEditor
editor = { editor }
className = "my-custom-editor"
/>
Inline styles to apply to the editor container. < YooptaEditor
editor = { editor }
style = {{ width : 750 , margin : '0 auto' }}
/>
renderBlock
(props: RenderBlockProps) => ReactNode
Custom render function for wrapping each block. Useful for implementing drag-and-drop or custom block decorations. The block data object containing id, type, value, and meta.
The unique identifier for the block.
The rendered block content (must be included in your custom wrapper).
< YooptaEditor
editor = { editor }
renderBlock = {({ block , blockId , children }) => (
< div
data-block- id = { blockId }
className = "draggable-block"
>
{ children }
</div>
)}
/>
Child components to render inside the editor, typically toolbars and menus. < YooptaEditor editor = { editor } >
< YooptaToolbar />
< YooptaSlashCommandMenu />
< YooptaActionMenuList />
</ YooptaEditor >
Usage Examples
Basic Usage
import { useMemo , useState } from 'react' ;
import { createYooptaEditor , YooptaEditor } from '@yoopta/editor' ;
import Paragraph from '@yoopta/paragraph' ;
function MyEditor () {
const editor = useMemo (() => createYooptaEditor ({
plugins: [ Paragraph ],
}), []);
return (
< YooptaEditor
editor = { editor }
placeholder = "Start typing..."
/>
);
}
With Change Handler and Persistence
import { useMemo , useState } from 'react' ;
import { createYooptaEditor , YooptaEditor } from '@yoopta/editor' ;
import type { YooptaContentValue } from '@yoopta/editor' ;
function MyEditor () {
const [ content , setContent ] = useState < YooptaContentValue >({});
const editor = useMemo (() => createYooptaEditor ({
plugins: [ Paragraph ],
value: content ,
}), []);
const handleChange = ( value : YooptaContentValue ) => {
setContent ( value );
// Auto-save to database
localStorage . setItem ( 'editor-content' , JSON . stringify ( value ));
};
return (
< YooptaEditor
editor = { editor }
onChange = { handleChange }
/>
);
}
import { YooptaEditor } from '@yoopta/editor' ;
import {
YooptaToolbar ,
YooptaSlashCommandMenu ,
YooptaActionMenuList ,
YooptaFloatingBlockActions
} from '@yoopta/ui' ;
function FullEditor () {
const editor = useMemo (() => createYooptaEditor ({
plugins: PLUGINS ,
marks: MARKS ,
}), []);
return (
< YooptaEditor
editor = { editor }
onChange = {(value) => console.log( 'Changed:' , value)}
placeholder = "Type / to open menu"
style = {{ width : 750 , margin : '0 auto' }}
>
< YooptaToolbar />
< YooptaSlashCommandMenu />
< YooptaActionMenuList />
< YooptaFloatingBlockActions />
</ YooptaEditor >
);
}
With Custom Block Wrapper (Drag & Drop)
import { YooptaEditor } from '@yoopta/editor' ;
import { useSortable } from '@dnd-kit/sortable' ;
function DraggableBlock ({ block , blockId , children }) {
const { attributes , listeners , setNodeRef } = useSortable ({
id: blockId
});
return (
< div ref = { setNodeRef } { ... attributes } >
< div className = "drag-handle" { ... listeners } >
⋮⋮
</ div >
{ children }
</ div >
);
}
function EditorWithDragDrop () {
const editor = useMemo (() => createYooptaEditor ({ plugins }), []);
return (
< YooptaEditor
editor = { editor }
renderBlock = {(props) => <DraggableBlock { ... props } />}
/>
);
}
Tracking Path Changes
function EditorWithPathTracking () {
const [ currentBlock , setCurrentBlock ] = useState < number | null >( null );
const editor = useMemo (() => createYooptaEditor ({ plugins }), []);
return (
< div >
< div > Current block : { currentBlock }</ div >
< YooptaEditor
editor = { editor }
onPathChange = {(path) => {
setCurrentBlock ( path . current );
console . log ( 'Selection source:' , path . source );
}}
/>
</ div >
);
}
Monitoring Operations
function EditorWithOperationTracking () {
const editor = useMemo (() => createYooptaEditor ({ plugins }), []);
const handleChange = ( value , { operations }) => {
// Track specific operations
operations . forEach ( op => {
switch ( op . type ) {
case 'insert_block' :
console . log ( 'Block inserted:' , op . block );
break ;
case 'delete_block' :
console . log ( 'Block deleted:' , op . block );
break ;
case 'move_block' :
console . log ( 'Block moved:' , op . prevProperties , '->' , op . properties );
break ;
}
});
};
return (
< YooptaEditor
editor = { editor }
onChange = { handleChange }
/>
);
}
Type Definitions
YooptaEditorProps
type YooptaEditorProps = {
editor : YooEditor ;
onChange ?: ( value : YooptaContentValue , options : YooptaOnChangeOptions ) => void ;
onPathChange ?: ( path : YooptaPath ) => void ;
autoFocus ?: boolean ;
className ?: string ;
children ?: React . ReactNode ;
placeholder ?: string ;
style ?: CSSProperties ;
renderBlock ?: ( props : RenderBlockProps ) => ReactNode ;
};
YooptaOnChangeOptions
type YooptaOnChangeOptions = {
operations : YooptaOperation [];
};
RenderBlockProps
type RenderBlockProps = {
block : YooptaBlockData ;
children : ReactNode ;
blockId : string ;
};
YooptaPath
type YooptaPath = {
current : number | null ;
selected ?: number [] | null ;
selection ?: Selection | null ;
source ?: 'selection-box' | 'native-selection' | 'mousemove' | 'keyboard' | 'copy-paste' | null ;
};
Important Notes
The onChange callback filters out internal operations (validate_block_paths, set_block_path, set_slate). Only user-facing operations are included in the operations array.
The editor automatically manages internal state updates. You don’t need to manually update the editor when content changes - just use the onChange callback to persist or track changes.
Use the renderBlock prop to integrate third-party drag-and-drop libraries like @dnd-kit/sortable or react-beautiful-dnd.
See Also