Skip to main content

Overview

YooptaBlockData represents a single content block in Yoopta Editor. Each block has a unique ID, type, content (value), and metadata that controls its ordering, depth, and alignment.

Type Definition

type YooptaBlockData<T = Descendant | SlateElement> = {
  id: string;
  value: T[];
  type: string;
  meta: YooptaBlockBaseMeta;
};

Properties

id
string
required
Unique identifier for the block. Typically a UUID generated when the block is created.
type
string
required
The plugin type identifier in PascalCase format (e.g., "Paragraph", "HeadingOne", "Blockquote"). This determines which plugin renders the block.
value
SlateElement[]
required
Array of Slate elements that make up the block’s content. Each element follows the SlateElement structure with kebab-case types.
meta
YooptaBlockBaseMeta
required
Metadata object containing the block’s order, depth, and alignment settings.

YooptaBlockBaseMeta

type YooptaBlockBaseMeta = {
  order: number;
  depth: number;
  align?: 'left' | 'center' | 'right' | undefined;
};

Examples

Paragraph Block

const paragraphBlock: YooptaBlockData = {
  id: "550e8400-e29b-41d4-a716-446655440000",
  type: "Paragraph",
  meta: {
    order: 0,
    depth: 0,
    align: "left"
  },
  value: [
    {
      id: "elem-1",
      type: "paragraph",
      children: [
        { text: "This is a simple paragraph with " },
        { text: "bold text", bold: true },
        { text: " and " },
        { text: "italic text", italic: true },
        { text: "." }
      ],
      props: {
        nodeType: "block"
      }
    }
  ]
};

Heading Block

const headingBlock: YooptaBlockData = {
  id: "block-heading-1",
  type: "HeadingOne",
  meta: {
    order: 1,
    depth: 0,
    align: "center"
  },
  value: [
    {
      id: "heading-elem-1",
      type: "heading-one",
      children: [
        { text: "Welcome to Yoopta Editor" }
      ],
      props: {
        nodeType: "block"
      }
    }
  ]
};

Nested List Block

const listBlock: YooptaBlockData = {
  id: "list-item-nested",
  type: "BulletedList",
  meta: {
    order: 5,
    depth: 1, // Nested one level deep
    align: "left"
  },
  value: [
    {
      id: "list-elem-1",
      type: "bulleted-list",
      children: [
        { text: "Nested list item" }
      ],
      props: {
        nodeType: "block"
      }
    }
  ]
};

Usage

Getting a Block

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

// Get a block by ID
const block = editor.getBlock({ id: 'block-id' });

if (block) {
  console.log('Block type:', block.type);
  console.log('Block order:', block.meta.order);
}

// Using Blocks API
const block2 = Blocks.getBlock(editor, { id: 'block-id' });

Creating a Block

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

// Build block data
const newBlock = Blocks.buildBlockData(editor, {
  type: 'Paragraph',
  value: [
    {
      id: 'elem-new',
      type: 'paragraph',
      children: [{ text: 'New paragraph' }],
      props: { nodeType: 'block' }
    }
  ],
  meta: {
    order: 0,
    depth: 0
  }
});

// Insert the block
editor.insertBlock(newBlock);

Updating a Block

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

// Update block metadata
editor.updateBlock('block-id', {
  meta: {
    ...currentBlock.meta,
    align: 'center'
  }
});

// Update block type (toggle)
editor.toggleBlock('block-id', {
  type: 'HeadingOne'
});

Working with Block Depth

// Increase depth (indent)
editor.increaseBlockDepth('block-id');

// Decrease depth (outdent)
editor.decreaseBlockDepth('block-id');

// Check current depth
const block = editor.getBlock({ id: 'block-id' });
if (block && block.meta.depth > 0) {
  console.log('Block is nested');
}

Type Naming Convention

Notice the dual naming convention:
  • Block type (YooptaBlockData.type): PascalCase (e.g., "Paragraph", "HeadingOne")
  • Element type (SlateElement.type): kebab-case (e.g., "paragraph", "heading-one")
This distinction is important when working with plugins and elements.

Iterating Over Block Values

const block = editor.getBlock({ id: 'block-id' });

if (block) {
  // Iterate over all elements in the block
  block.value.forEach((element) => {
    console.log('Element type:', element.type);
    console.log('Element children:', element.children);
  });
}

Event Handling

// Listen for block copy events
editor.on('block:copy', (blockData: YooptaBlockData) => {
  console.log('Block copied:', blockData.id);
  console.log('Block type:', blockData.type);
});

// Listen for content changes
editor.on('change', ({ value, operations }) => {
  // value is YooptaContentValue (Record<string, YooptaBlockData>)
  operations.forEach((op) => {
    if (op.type === 'insert_block') {
      console.log('New block inserted:', op.block);
    }
  });
});

Type Safety

import type { YooptaBlockData, YooptaBlockBaseMeta } from '@yoopta/editor';

function processBlock(block: YooptaBlockData) {
  // Type-safe access to properties
  const { id, type, meta, value } = block;
  
  // TypeScript ensures meta has required properties
  console.log(`Block ${id} at order ${meta.order}`);
}

function updateBlockMeta(meta: YooptaBlockBaseMeta): YooptaBlockBaseMeta {
  return {
    ...meta,
    align: 'center' // Type-checked
  };
}

See Also

Build docs developers (and LLMs) love