Blocks API: вставка, перенос и удаление блоков
Управление блоками в редакторе — создание, удаление, обновление и переупорядочивание контента.
Как получить экземпляр редактора
Методы ниже вызываются на редакторе, созданном через new Blok(). Они доступны после того, как разрешится editor.isReady.
// You already hold the instance returned by the constructor.
const editor = new Blok({ holder: 'editor' });
await editor.isReady;
// Call any API method on it.
editor.caret.setToLastBlock('end');Методы
blocks.clear()
Promise<void>Remove all blocks from the editor.
Когда использовать
То же, что clear() верхнего уровня, но на модуле blocks. Используйте, когда уже есть ссылка на editor.blocks.
await editor.blocks.clear();
// All content removed; editor keeps one empty paragraphblocks.render(data)
Promise<void>Render passed JSON data as blocks, replacing the current document. Echo-safe: when the incoming document is structurally equal to the current saved content (`time`/`version` ignored), the call is a caret-preserving no-op — the `data → render → onSave → setState → data` round-trip needs no consumer-side dedupe. Accepts the loose wire shape (`LooseOutputData`); the editor deep-clones the data, so the passed object is never mutated or retained — frozen store state (Redux, Immer) can be passed directly.
Когда использовать
Заменяет весь документ. Повторная передача собственного вывода редактора — no-op с сохранением каретки, дедупликация на стороне потребителя не нужна. Чтобы добавить блоки без очистки, используйте insert() или insertMany().
const data = {
blocks: [
{ id: '1', type: 'paragraph', data: { text: 'Hello World' } },
{ id: '2', type: 'header', data: { text: 'Title', level: 1 } }
]
};
await editor.blocks.render(data);blocks.renderFromHTML(data)
Promise<void>Render HTML string as blocks by converting it to block format.
Когда использовать
Удобно для импорта старого HTML, но результат зависит от обработчиков вставки инструментов — JSON через render() сохраняет больше точности, когда источник под контролем.
const html = '<h1>Title</h1><p>Hello World</p>';
await editor.blocks.renderFromHTML(html);
// HTML is converted to appropriate blocksblocks.delete(index?, setCaret?)
Promise<void>Remove the block at the specified index, or current block if no index provided.
Когда использовать
Без индекса удаляет блок в фокусе. Удаление последнего оставшегося блока автоматически вставляет свежий пустой параграф, поэтому редактор никогда не остаётся без цели для курсора.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
index | number | — | current block index | Index of the block to delete. |
setCaret | boolean | — | true | Whether to move the caret to the surviving block after deletion; pass false to avoid stealing the user's caret during programmatic deletion. |
// Delete current block
await editor.blocks.delete();
// Delete block at index 0
await editor.blocks.delete(0);
// Delete without moving the user's caret (programmatic deletion)
await editor.blocks.delete(0, false);blocks.move(toIndex, fromIndex?)
voidMoves a block to a new position. If fromIndex is not provided, moves the current block.
Когда использовать
toIndex — это индекс после удаления: при перемещении вперёд вычтите 1, иначе блок встанет на позицию дальше нужной.
// Move current block to top
editor.blocks.move(0);
// Move block from index 2 to index 0
editor.blocks.move(0, 2);blocks.getBlockByIndex(index)
BlockAPI | undefinedGet the BlockAPI object for the block at the specified index.
Когда использовать
Возвращает undefined для индексов вне диапазона — вызов метода на undefined приведёт к ошибке, поэтому сначала проверьте результат.
const block = editor.blocks.getBlockByIndex(0);
if (block) {
console.log(block.id, block.name);
}blocks.getById(id)
BlockAPI | nullGet the BlockAPI object for the block with the specified ID.
Когда использовать
Надёжный способ ссылаться на блок между правками, так как индексы смещаются. Возвращает null, если id больше не существует.
const block = editor.blocks.getById('block-123');
if (block) {
await editor.blocks.update(block.id, { text: 'New content' });
}blocks.getCurrentBlockIndex()
numberGet the index of the currently focused block.
Когда использовать
Отражает блок с курсором. Возвращает -1, когда ничего не в фокусе, — проверяйте перед использованием как индекс.
const index = editor.blocks.getCurrentBlockIndex();
console.log('Current block index:', index);blocks.getBlockIndex(blockId)
number | undefinedGet the index of a block by its ID.
Когда использовать
Узнаёт текущую позицию известного блока; сочетайте с getById(), когда есть id, а нужна позиция.
const index = editor.blocks.getBlockIndex('block-123');
if (index !== undefined) {
console.log('Block is at index:', index);
}blocks.getBlockByElement(element)
BlockAPI | undefinedGet the BlockAPI object for the block containing the given HTML element.
Когда использовать
Мост от DOM-узла (например, цели клика) обратно к его блоку — полезно в собственных обработчиках.
document.addEventListener('click', (e) => {
const block = editor.blocks.getBlockByElement(e.target);
if (block) {
console.log('Clicked on block:', block.id);
}
});blocks.getChildren(parentId)
BlockAPI[]Get all child blocks of a parent container block.
Когда использовать
Возвращает прямых потомков блока-контейнера (колонки, тоггла или базы данных). Пустой массив, если потомков нет.
const children = editor.blocks.getChildren('parent-block-id');
children.forEach(child => {
console.log('Child:', child.id);
});blocks.getBlocksCount()
numberGet the total number of blocks in the editor.
Когда использовать
Считает все блоки, включая вложенные дочерние (колонки, тогглы, ячейки таблиц), а не только блоки верхнего уровня. Используйте для границ перед insert() или move() по индексу.
const count = editor.blocks.getBlocksCount();
console.log('Total blocks:', count);blocks.insert(type?, data?, config?, index?, needToFocus?, replace?, id?, tunes?)
BlockAPIInsert a new block with full control over its properties and position.
Когда использовать
Все параметры необязательны — insert() даёт пустой параграф, либо передайте type/data/index для контроля. replace: true заменяет блок по индексу index.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
type | string | — | config.defaultBlock | Имя инструмента для создания блока. |
data | BlockToolData | — | {} | Начальные данные инструмента для нового блока. |
config | ToolConfig | — | {} | Конфигурация инструмента для этого экземпляра блока. |
index | number | — | current block index + 1 | Позиция для вставки блока. |
needToFocus | boolean | — | true | Переводить ли фокус на вставленный блок. |
replace | boolean | — | false | Заменить существующий блок по индексу вместо вставки рядом с ним. |
id | string | — | auto-generated | Собственный id для нового блока. |
tunes | { [name: string]: BlockTuneData } | — | undefined | Необязательные данные тюнов, применяемые при создании, с ключами по имени тюна. |
Ошибки
Не указан
type, и в конфигурации не заданdefaultBlock.Could not insert Block. Tool name is not specified.
Передайте явный
typeили задайтеdefaultBlockв конфигурации редактора.Определённое имя инструмента не зарегистрировано в редакторе.
Could not compose Block. Tool «<type>» not found.
Зарегистрируйте инструмент в конфигурации
toolsредактора перед вставкой блока этого типа.Передан
replace: true, но поindexнет блока.Could not replace Block at index <index>. Block not found.
Проверьте
indexчерезblocks.getBlocksCount()перед вызовом сreplace: true.
// Insert after the current block with the default type
const block = editor.blocks.insert();
// → BlockAPI { id: 'kP3xQ...', name: 'paragraph', ... }
// Insert paragraph with data at index 0
const block = editor.blocks.insert('paragraph', { text: 'Hello' }, undefined, 0);
// Insert with custom ID
const block = editor.blocks.insert('header', { text: 'Title' }, undefined, undefined, undefined, undefined, 'custom-id');blocks.insertMany(blocks, index?)
BlockAPI[]Insert multiple blocks at once. When the index is omitted, the blocks are appended at the end of the document.
Когда использовать
Массовая вставка за одну операцию (и один шаг отмены) — гораздо дешевле цикла из insert() для больших вставок или импорта.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
blocks | OutputBlockData[] | LooseOutputBlockData[] | Обязательный | — | The blocks to insert. Loose wire blocks are accepted — a null data becomes {}, a null/empty id gets a generated one. |
index | number | — | end of document | Position to insert at. When omitted, defaults to appending at the end of the document. |
Ошибки
The provided
indexis negative.Index should be greater than or equal to 0
Pass an
indexof 0 or greater, or omit it to append.
const blocksToInsert = [
{ id: '1', type: 'paragraph', data: { text: 'First' } },
{ id: '2', type: 'paragraph', data: { text: 'Second' } }
];
const inserted = editor.blocks.insertMany(blocksToInsert, 0);
console.log('Inserted:', inserted.length, 'blocks');blocks.composeBlockData(toolName)
Promise<BlockToolData>Create empty block data for the specified tool type.
Когда использовать
Создаёт данные инструмента по умолчанию, ничего не вставляя — удобно, когда нужен корректный пустой payload для insert() или update().
Ошибки
toolNameis not a registered tool.Block Tool with type "<toolName>" not found
Register the tool in the editor's
toolsconfig first.
const emptyData = await editor.blocks.composeBlockData('paragraph');
// Returns: { text: '' } or appropriate empty state for the toolblocks.update(id, data?, tunes?)
Promise<BlockAPI>Update a block's data and/or tunes.
Когда использовать
Изменяет data/tunes на месте, сохраняя id и тип блока. Чтобы сменить тип, используйте convert().
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
id | string | Обязательный | — | Id блока для обновления. |
data | Partial<BlockToolData> | — | undefined | Частичные данные, объединяемые с существующими данными блока. |
tunes | Record<string, BlockTuneData> | — | undefined | Данные тюнов, объединяемые с существующими тюнами блока. |
Ошибки
Блок с указанным
idне существует.Block with id "<id>" not found
Проверьте id через
blocks.getById()перед вызовомupdate().
// Update block data
const block = await editor.blocks.update('block-123', { text: 'New text' });
// Update with tunes
const block = await editor.blocks.update('block-123', undefined, { alignment: 'center' });
// Guard against an id that no longer exists (e.g. the block was deleted
// concurrently) instead of letting the rejection surface unhandled
try {
await editor.blocks.update(staleId, { text: 'New text' });
} catch {
console.warn('Block was already removed, skipping update');
}blocks.convert(id, newType, dataOverrides?)
Promise<BlockAPI>Convert a block to a different type. Both tools must support conversion config.
Когда использовать
И исходный, и целевой инструменты должны объявлять conversionConfig, иначе вызов выбросит ошибку. По возможности сохраняет текст.
Параметры
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
id | string | Обязательный | — | Id блока для конвертации. Его инструмент должен объявлять conversionConfig.export. |
newType | string | Обязательный | — | Имя зарегистрированного инструмента для конвертации. Его инструмент должен объявлять conversionConfig.import. |
dataOverrides | BlockToolData | — | undefined | Поля данных для перезаписи в результирующем блоке после конвертации. |
Ошибки
Блок с указанным
idне существует.Block with id "<id>" not found
Проверьте id через
blocks.getById()перед вызовомconvert().newTypeне является зарегистрированным инструментом.Block Tool with type "<newType>" not found
Зарегистрируйте целевой инструмент в конфигурации
toolsредактора.У исходного инструмента нет
conversionConfig.export, у целевого нетconversionConfig.import, либо нет ни того, ни другого.Conversion from "<sourceType>" to "<newType>" is not possible. <ToolName(s)> tool(s) should provide a "conversionConfig"
Добавьте
conversionConfigтому инструменту, у которого его нет, либо конвертируйте через промежуточный инструмент, поддерживающий оба направления.
// Convert paragraph to header
const headerBlock = await editor.blocks.convert('block-123', 'header', { level: 2 });
// Convert with data overrides
const headerBlock = await editor.blocks.convert('block-123', 'header', { text: 'New Title', level: 1 });
// Not every pair of tools supports conversion — guard it rather than
// assuming the target type is always convertible
try {
await editor.blocks.convert('block-123', 'table');
} catch (error) {
console.warn('Conversion not supported between these tools:', error);
}blocks.splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex)
BlockAPIAtomically split a block by updating the current block and inserting a new block. Both operations are grouped into a single undo entry.
Когда использовать
Используйте для разбиения с учётом курсора (например, Enter посреди текста); update и insert образуют один шаг отмены.
// Split a paragraph at cursor position
const newBlock = editor.blocks.splitBlock(
'current-block-id',
{ text: 'First part' },
'paragraph',
{ text: 'Second part' },
1
);blocks.stopBlockMutationWatching(index)
voidStop mutation watching on a block at the specified index. Use this to prevent spurious block-changed events during block replacement operations.
Когда использовать
Нишевое: вызывайте перед программной заменой DOM блока, чтобы подавить ложные события block-changed; следующий рендер включит наблюдение снова.
// Replace a block without triggering change events
editor.blocks.stopBlockMutationWatching(0);
// Perform block replacement...
// Mutation observer will not fire for this block