Skip to main content

Overview

The insertElement method creates and inserts a new element into a block at a specified position.

Signature

editor.insertElement(options: InsertElementOptions): void

Parameters

options
InsertElementOptions
required
Configuration object for inserting the element

Examples

Basic Usage

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

function AccordionControls({ blockId }: Props) {
  const editor = useYooptaEditor();

  const addItem = () => {
    editor.insertElement({
      blockId,
      type: 'accordion-list-item',
      props: { isExpanded: true },
      at: 'end',
      focus: true,
    });
  };

  return <button onClick={addItem}>Add Item</button>;
}

Insert with Children

// Insert accordion item with custom children
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  props: { isExpanded: false },
  children: [
    editor.y('accordion-list-item-heading', {
      children: [editor.y.text('New Item Title')]
    }),
    editor.y('accordion-list-item-content', {
      children: [editor.y.text('Item content here')]
    })
  ],
  at: 'next',
});

Insert at Specific Position

// Insert at specific path
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  props: { isExpanded: true },
  at: [0, 2], // Insert at third position
});

// Insert at start
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  at: 'start',
});

// Insert at end
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  at: 'end',
});

Insert Relative to Current Element

// Insert after current item (next)
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  at: 'next', // Inserts after the current accordion-list-item
  focus: true,
});

// Insert before current item (prev)
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  at: 'prev', // Inserts before the current accordion-list-item
});
// Insert link at current selection
editor.insertElement({
  blockId: 'paragraph-1',
  type: 'link',
  props: { url: 'https://example.com', target: '_blank' },
  text: 'Click here',
  at: 'selection',
});

Insert Table Row

// Insert new table row
editor.insertElement({
  blockId: 'table-1',
  type: 'table-row',
  children: [
    editor.y('table-data-cell', { children: [editor.y.text('Cell 1')] }),
    editor.y('table-data-cell', { children: [editor.y.text('Cell 2')] }),
    editor.y('table-data-cell', { children: [editor.y.text('Cell 3')] }),
  ],
  at: 'next',
});

Insert Tab

const addTab = (blockId: string) => {
  const tabId = generateId();

  // Insert tab heading
  editor.insertElement({
    blockId,
    type: 'tabs-item-heading',
    props: { id: tabId, active: false },
    children: [editor.y.text('New Tab')],
    at: 'end',
  });

  // Insert corresponding tab content
  editor.insertElement({
    blockId,
    type: 'tabs-item-content',
    props: { referenceId: tabId },
    at: 'end',
  });
};

Use Cases

Add Accordion Item

const addAccordionItem = (blockId: string, afterIndex?: number) => {
  const at = afterIndex !== undefined ? [0, afterIndex + 1] : 'end';

  editor.insertElement({
    blockId,
    type: 'accordion-list-item',
    props: { isExpanded: false },
    at,
    focus: true, // Focus the new item for immediate editing
  });
};

Insert Step

const addStep = (blockId: string) => {
  editor.insertElement({
    blockId,
    type: 'step-list-item',
    props: { isCompleted: false },
    children: [
      editor.y('step-list-item-content', {
        children: [editor.y.text('New step description')]
      })
    ],
    at: 'end',
  });
};

Insert with Default Children

// If children not provided, plugin defaults will be used
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  props: { isExpanded: true },
  // Children will be created from plugin configuration
  at: 'next',
});

Batch Insert

const addMultipleItems = (blockId: string, count: number) => {
  for (let i = 0; i < count; i++) {
    editor.insertElement({
      blockId,
      type: 'accordion-list-item',
      props: { isExpanded: false },
      at: 'end',
    });
  }
};

Advanced Usage

Insert with Custom Matcher

// Insert after a specific element found by matcher
editor.insertElement({
  blockId: 'accordion-1',
  type: 'accordion-list-item',
  at: 'next',
  match: (el) => el.type === 'accordion-list-item' && el.props?.id === 'target-item',
});

Conditional Insert

const insertIfNotExists = (blockId: string, itemId: string) => {
  const exists = editor.getElement({
    blockId,
    match: (el) => el.type === 'accordion-list-item' && el.props?.id === itemId,
  });

  if (!exists) {
    editor.insertElement({
      blockId,
      type: 'accordion-list-item',
      props: { id: itemId },
      at: 'end',
    });
  }
};

Notes

If children are not provided, the method will automatically create default children based on the plugin’s element configuration. This is useful when you want to insert elements with their standard structure.
The at option 'next' and 'prev' require a current selection or a matching element of the same type. If no selection exists, it will fallback to inserting at the end of the block.
When focus is true, the editor will focus the first child element if the inserted element has children. This is useful for immediately allowing the user to start typing.
The element type must be a valid element type defined in the block’s plugin. Inserting an invalid type will silently fail.
For inline elements (like link, mention), you can use the text parameter to set the text content. For block elements, use the children parameter instead.

Type Definition

type InsertElementOptions = {
  blockId: string;
  type: string;
  props?: Record<string, unknown>;
  children?: SlateElement[];
  at?: 'next' | 'prev' | 'start' | 'end' | number[];
  focus?: boolean;
  select?: boolean;
  text?: string;
  match?: (element: SlateElement) => boolean;
};