Skip to main content

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

editor
YooEditor
required
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.
<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.
autoFocus
boolean
default:"false"
Whether to automatically focus the editor on mount.
<YooptaEditor editor={editor} autoFocus />
placeholder
string
Placeholder text to show when the editor is empty.
<YooptaEditor 
  editor={editor} 
  placeholder="Type / to open command menu..."
/>
className
string
CSS class name to apply to the editor container.
<YooptaEditor 
  editor={editor} 
  className="my-custom-editor"
/>
style
CSSProperties
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.
<YooptaEditor
  editor={editor}
  renderBlock={({ block, blockId, children }) => (
    <div 
      data-block-id={blockId}
      className="draggable-block"
    >
      {children}
    </div>
  )}
/>
children
ReactNode
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}
    />
  );
}

With Toolbars and Menus

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

Build docs developers (and LLMs) love