Skip to main content

Overview

The Blocks API provides a comprehensive interface for working with blocks in Yoopta Editor. It handles all block-level operations including creation, deletion, movement, transformation, and navigation.
The Blocks API is the primary way to manipulate the structure of your editor content. It works at a higher level than the Elements API, operating on entire blocks rather than individual elements within blocks.

Accessing Blocks API

Blocks API methods are available through the Blocks namespace:
import { Blocks } from '@yoopta/editor';

// Use methods through Blocks namespace
Blocks.insertBlock(editor, 'Paragraph', { at: 0 });
Blocks.deleteBlock(editor, { at: 3 });
Blocks.moveBlock(editor, 'block-id', 5);
Unlike Elements API, Blocks API methods are not available directly on the editor instance. You must use the Blocks namespace.

Why Blocks API?

  • Block-Level Operations: Work with entire blocks, not just elements
  • Structure Management: Handle block ordering, depth, and relationships
  • Type Safety: Full TypeScript support with proper type inference
  • Lifecycle Hooks: Integrates with plugin lifecycle methods
  • Focus Management: Built-in focus handling for better UX

Core Methods

The Blocks API consists of several categories:

CRUD Operations

Transformation

Depth Management

Utilities

Quick Example

import { Blocks } from '@yoopta/editor';
import { useYooptaEditor } from '@yoopta/editor';

function MyComponent() {
  const editor = useYooptaEditor();

  const handleAddParagraph = () => {
    // Insert new paragraph block
    const blockId = Blocks.insertBlock(editor, 'Paragraph', {
      at: editor.path.current,
      focus: true,
    });
  };

  const handleDeleteBlock = () => {
    // Delete current block
    Blocks.deleteBlock(editor, {
      at: editor.path.current,
      focusTarget: 'previous',
    });
  };

  const handleToggleToHeading = () => {
    // Transform current paragraph to heading
    Blocks.toggleBlock(editor, 'Heading', {
      preserveContent: true,
      focus: true,
    });
  };

  return (
    // Your component JSX
  );
}

Common Use Cases

Inserting Blocks

// Insert paragraph at current position
Blocks.insertBlock(editor, 'Paragraph', {
  at: editor.path.current,
  focus: true,
});

// Insert heading with custom content
Blocks.insertBlock(editor, 'Heading', {
  at: 0,
  elements: editor.y('heading-one', {
    children: [editor.y.text('New Heading')]
  }),
});

Moving and Reordering

// Move block to new position
Blocks.moveBlock(editor, 'block-id-123', 5);

// Increase block depth (indent)
Blocks.increaseBlockDepth(editor, { blockId: 'block-id-123' });

// Decrease block depth (outdent)
Blocks.decreaseBlockDepth(editor, { at: 3 });

Transforming Blocks

// Toggle paragraph to heading
Blocks.toggleBlock(editor, 'Heading', {
  preserveContent: true,
});

// Split block at current selection
const newBlockId = Blocks.splitBlock(editor, {
  focusTarget: 'new',
});

// Merge current block into previous
Blocks.mergeBlock(editor);

Type Definitions

Common Types

// Block path/index specification
type YooptaPathIndex = number;

// Block data structure
type YooptaBlockData = {
  id: string;
  type: string;
  value: SlateElement[];
  meta: {
    order: number;
    depth: number;
    align?: 'left' | 'center' | 'right';
  };
};

Best Practices

Always specify at or blockId when working with specific blocks. Using editor.path.current is convenient but can be unreliable if the path changes.

1. Use Block IDs When Possible

// ✅ Good - using block ID
Blocks.deleteBlock(editor, { blockId: 'block-123' });

// ⚠️ Acceptable - using path
Blocks.deleteBlock(editor, { at: 3 });

2. Handle Focus Appropriately

// Focus after insertion for better UX
Blocks.insertBlock(editor, 'Paragraph', {
  at: editor.path.current,
  focus: true, // User can immediately start typing
});

// Don't focus when doing batch operations
for (let i = 0; i < 10; i++) {
  Blocks.insertBlock(editor, 'Paragraph', {
    at: i,
    focus: false, // Don't focus each block
  });
}

3. Preserve Content When Transforming

// ✅ Good - preserve user's content
Blocks.toggleBlock(editor, 'Heading', {
  preserveContent: true,
});

// ❌ Avoid - loses user content
Blocks.toggleBlock(editor, 'Heading', {
  preserveContent: false,
});

4. Check Block Existence

const block = Blocks.getBlock(editor, { at: 3 });

if (block) {
  Blocks.updateBlock(editor, block.id, {
    meta: { align: 'center' },
  });
}

Next Steps