🚀 BlockNote AI is here! Access the early preview.
BlockNote Docs/Editor Reference/Manipulating Content

Manipulating Content

BlockNote provides comprehensive APIs for manipulating both blocks and inline content within the editor. This guide covers how to programmatically work with the document structure (blocks) and the content within those blocks (text, links, styling).

Overview

The content manipulation APIs fall into two main categories:

Block Manipulation

Inline Content Manipulation

Common Types

Block Identifiers

Most block methods require a BlockIdentifier to reference existing blocks:

type BlockIdentifier = string | Block;

You can pass either:

  • A string representing the block ID
  • A Block object (the ID will be extracted automatically)

Partial Blocks

When creating or updating blocks, you use PartialBlock objects which have optional properties:

type PartialBlock = {
  id?: string; // Auto-generated if not provided
  type?: string; // Block type (paragraph, heading, etc.)
  props?: Partial<Record<string, any>>; // Block-specific properties
  content?: string | InlineContent[] | TableContent; // Block content
  children?: PartialBlock[]; // Nested blocks
};

Partial Inline Content

When creating or updating inline content, you use PartialInlineContent which allows for flexible content specification:

type PartialLink = {
  type: "link";
  content: string | StyledText[];
  href: string;
};

type PartialInlineContent = string | (string | PartialLink | StyledText)[];

This type allows you to:

  • Pass a simple string for plain text
  • Pass an array of mixed content (strings, links, styled text)
  • Use PartialLink for link content
  • Use StyledText for text with formatting

Block Manipulation

Reading Blocks

Getting the Document

Retrieve all top-level blocks in the editor:

const blocks = editor.document;

Returns a snapshot of all top-level (non-nested) blocks in the document.

Getting Specific Blocks

// Single block
getBlock(blockIdentifier: BlockIdentifier): Block | undefined

// Previous block
getPrevBlock(blockIdentifier: BlockIdentifier): Block | undefined

// Next block
getNextBlock(blockIdentifier: BlockIdentifier): Block | undefined

// Parent block
getParentBlock(blockIdentifier: BlockIdentifier): Block | undefined
const block = editor.getBlock("block-123");
const prevBlock = editor.getPrevBlock("block-123");
const nextBlock = editor.getNextBlock("block-123");
const parentBlock = editor.getParentBlock("nested-block-123");

Traversing All Blocks

forEachBlock(
  callback: (block: Block) => boolean | undefined,
  reverse: boolean = false
): void

Traverses all blocks depth-first and executes a callback for each.

editor.forEachBlock((block) => {
  console.log(`Block ${block.id}: ${block.type}`);
  return true; // Continue traversal
});

Creating Blocks

Inserting Blocks

insertBlocks(
  blocksToInsert: PartialBlock[],
  referenceBlock: BlockIdentifier,
  placement: "before" | "after" = "before"
): void

Inserts new blocks relative to an existing block.

// Insert a paragraph before an existing block
editor.insertBlocks(
  [{ type: "paragraph", content: "New paragraph" }],
  "existing-block-id",
  "before",
);

// Insert multiple blocks after an existing block
editor.insertBlocks(
  [
    { type: "heading", content: "New Section", props: { level: 2 } },
    { type: "paragraph", content: "Section content" },
  ],
  "existing-block-id",
  "after",
);

Updating Blocks

Modifying Existing Blocks

updateBlock(
  blockToUpdate: BlockIdentifier,
  update: PartialBlock
): void

Updates an existing block with new properties.

// Change a paragraph to a heading
editor.updateBlock("block-123", {
  type: "heading",
  props: { level: 2 },
});

// Update content only
editor.updateBlock("block-123", {
  content: "Updated content",
});

// Update multiple properties
editor.updateBlock("block-123", {
  type: "heading",
  content: "New heading text",
  props: { level: 1 },
});

Removing Blocks

Deleting Blocks

removeBlocks(blocksToRemove: BlockIdentifier[]): void

Removes one or more blocks from the document.

// Remove a single block
editor.removeBlocks(["block-123"]);

// Remove multiple blocks
editor.removeBlocks(["block-123", "block-456", "block-789"]);

Replacing Blocks

Swapping Blocks

replaceBlocks(
  blocksToRemove: BlockIdentifier[],
  blocksToInsert: PartialBlock[]
): void

Replaces existing blocks with new ones.

// Replace a paragraph with a heading
editor.replaceBlocks(
  ["paragraph-block"],
  [{ type: "heading", content: "New Heading", props: { level: 2 } }],
);

// Replace multiple blocks with different content
editor.replaceBlocks(
  ["block-1", "block-2"],
  [
    { type: "paragraph", content: "Replacement content" },
    { type: "bulletListItem", content: "List item" },
  ],
);

Moving Blocks

Reordering Blocks

moveBlocksUp(): void
moveBlocksDown(): void

Moves the currently selected blocks up or down in the document.

// Move selected blocks up
editor.moveBlocksUp();

// Move selected blocks down
editor.moveBlocksDown();

Nesting Blocks

Creating Hierarchical Structures

canNestBlock(): boolean
nestBlock(): void
canUnnestBlock(): boolean
unnestBlock(): void

Manages the nesting level of blocks (indentation).

// Check if current block can be nested
if (editor.canNestBlock()) {
  editor.nestBlock(); // Indent the block
}

// Check if current block can be un-nested
if (editor.canUnnestBlock()) {
  editor.unnestBlock(); // Outdent the block
}

Inline Content Manipulation

Inserting Inline Content

Basic Insertion

insertInlineContent(
  content: PartialInlineContent,
  options?: { updateSelection?: boolean }
): void

Inserts content at the current cursor position or replaces the current selection.

// Insert plain text
editor.insertInlineContent("Hello, world!");

// Insert mixed content
editor.insertInlineContent([
  "Hello ",
  { type: "text", text: "World", styles: { bold: true } },
  "! Welcome to ",
  { type: "link", content: "BlockNote", href: "https://blocknotejs.org" },
]);

// Insert with selection update
editor.insertInlineContent("New content", { updateSelection: true });

Advanced Content Examples

// Insert styled text
editor.insertInlineContent([
  {
    type: "text",
    text: "Bold and italic",
    styles: { bold: true, italic: true },
  },
]);

// Insert link with styled content
editor.insertInlineContent([
  {
    type: "link",
    content: [
      { type: "text", text: "Visit ", styles: {} },
      { type: "text", text: "BlockNote", styles: { bold: true } },
    ],
    href: "https://blocknotejs.org",
  },
]);

// Insert complex mixed content
editor.insertInlineContent([
  "This is ",
  { type: "text", text: "important", styles: { bold: true, textColor: "red" } },
  " and you should ",
  { type: "link", content: "read more", href: "https://example.com" },
  " about it.",
]);

Reading Content

Getting Selected Text

getSelectedText(): string

Retrieves the currently selected text as a plain string.

const selectedText = editor.getSelectedText();
console.log("Selected text:", selectedText);

// Example: Copy selected text to clipboard
if (selectedText) {
  navigator.clipboard.writeText(selectedText);
}

Getting Active Styles

getActiveStyles(): Styles

Returns the active text styles at the current cursor position or at the end of the current selection.

const activeStyles = editor.getActiveStyles();
console.log("Active styles:", activeStyles);

// Example: Check if text is bold
if (activeStyles.bold) {
  console.log("Text is bold");
}

// Example: Get text color
if (activeStyles.textColor) {
  console.log("Text color:", activeStyles.textColor);
}
getSelectedLinkUrl(): string | undefined

Returns the URL of the last link in the current selection, or undefined if no links are selected.

const linkUrl = editor.getSelectedLinkUrl();

if (linkUrl) {
  console.log("Selected link URL:", linkUrl);
  // Open link in new tab
  window.open(linkUrl, "_blank");
} else {
  console.log("No link selected");
}

Styling Text

Adding Styles

addStyles(styles: Styles): void

Applies styles to the currently selected text.

// Add single style
editor.addStyles({ bold: true });

// Add multiple styles
editor.addStyles({
  bold: true,
  italic: true,
  textColor: "red",
});

// Add background color
editor.addStyles({ backgroundColor: "yellow" });

Removing Styles

removeStyles(styles: Styles): void

Removes specific styles from the currently selected text.

// Remove single style
editor.removeStyles({ bold: true });

// Remove multiple styles
editor.removeStyles({ bold: true, italic: true });

// Remove color styles
editor.removeStyles({ textColor: "red", backgroundColor: "yellow" });

Toggling Styles

toggleStyles(styles: Styles): void

Toggles styles on the currently selected text (adds if not present, removes if present).

// Toggle single style
editor.toggleStyles({ bold: true });

// Toggle multiple styles
editor.toggleStyles({ bold: true, italic: true });

// Toggle color
editor.toggleStyles({ textColor: "blue" });
createLink(url: string, text?: string): void

Creates a new link, optionally replacing the currently selected text.

// Create link from selected text
editor.createLink("https://blocknotejs.org");

// Create link with custom text
editor.createLink("https://blocknotejs.org", "Visit BlockNote");

// Create link with empty URL (removes link)
editor.createLink("");

Combining Block and Inline Content

Here are some examples of how to combine block and inline content manipulation:

Creating a Rich Document Structure

// Create a document with rich content
editor.insertBlocks(
  [
    {
      type: "heading",
      content: [
        { type: "text", text: "Welcome to ", styles: {} },
        {
          type: "text",
          text: "BlockNote",
          styles: { bold: true, textColor: "blue" },
        },
      ],
      props: { level: 1 },
    },
    {
      type: "paragraph",
      content: [
        "This is a ",
        { type: "text", text: "powerful", styles: { italic: true } },
        " editor that supports ",
        {
          type: "link",
          content: "rich formatting",
          href: "https://blocknotejs.org",
        },
        " and ",
        { type: "text", text: "structured content", styles: { bold: true } },
        ".",
      ],
    },
  ],
  "existing-block-id",
  "after",
);

Updating Block Content with Styling

// Update a block with styled content
editor.updateBlock("block-123", {
  content: [
    "Updated with ",
    { type: "text", text: "styled", styles: { bold: true, textColor: "red" } },
    " content and a ",
    { type: "link", content: "link", href: "https://example.com" },
    ".",
  ],
});

Reading and Manipulating Complex Content

// Get selected text and create a new block with it
const selectedText = editor.getSelectedText();
if (selectedText) {
  editor.insertBlocks(
    [
      {
        type: "paragraph",
        content: [
          "Selected text: ",
          {
            type: "text",
            text: selectedText,
            styles: { backgroundColor: "yellow" },
          },
        ],
      },
    ],
    "current-block-id",
    "after",
  );
}