---
title: "Компонент BlokEditor для React — справочник"
description: "Все пропсы BlokEditor: data, tools, onChange, onSave, readOnly, onReady и императивный API через ref."
source: https://blokeditor.com/ru/docs/blok-editor/
lastmod: 2026-09-07
---

Фреймворк JavaScript

Адаптеры фреймворков Компонент BlokEditor

На этой странице useBlok(config, deps?)

# React-компонент BlokEditor

Компонент-редактор «всё в одном», который поставляют адаптеры фреймворков: <BlokEditor> в @bloklabs/react и @bloklabs/vue, <blok-editor> (BlokEditorComponent) в @bloklabs/angular. React и Vue принимают любую опцию конфигурации редактора как проп и пробрасывают неизвестные пропы/атрибуты на контейнерный div. Angular устроен иначе: он объявляет ограниченный набор `@Input()` — tools, data, readOnly, hideToolbar, toolbarPosition, inlineToolbar, theme, width, placeholder, styleTokens, i18n, autofocus, migrations, onBeforeRender, onBeforePaste, onError — плюс запасной вход `[config]` для всех остальных ключей конфигурации (sanitizer, minHeight, defaultBlock, dataModel, link, linkPaste, tunes, user, resolveUser, uploader, server, ticket, persistence, collaboration, notifier, logLevel, onEnter, onSubmit, scrollToBlock, …) и не пробрасывает атрибуты хоста на контейнерный div. Живой экземпляр Blok читается через ref/onReady (React), через `instance` на шаблонной ссылке или эмит `@ready` (Vue) и через сигнал `instance` или output `(ready)` (Angular). Пропы ниже описывают специфичную для адаптеров поверхность; остальное совпадает с опциями раздела «Конфигурация».

Обновлено 17 июл. 2026 г. [Редактировать на GitHub](https://github.com/JackUait/blok/blob/main/docs/src/components/api/api-data.ts)

### Как получить экземпляр редактора

Методы ниже вызываются на редакторе, созданном через new Blok(). Они доступны после того, как разрешится editor.isReady.

TypeScript

```
// 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');
```

## Методы

### useBlok(config, deps?)

Blok | null (React) | Ref<Blok | null> (Vue)

Раздельный путь монтирования, стоящий за `<BlokEditor>`: экземпляр вы создаёте сами и передаёте ему точку монтирования. `useBlok` принимает ТЕ ЖЕ опции, что и компонент, — его тип конфигурации `UseBlokConfig`, то есть `BlokConfig` без `holder` (элементом монтирования владеет адаптер) плюс `width` уровня адаптера. Подмножество, реактивное после монтирования, описано на самом `UseBlokConfig`: `readOnly`, `hideToolbar`, `toolbarPosition`, `inlineToolbar`, `autofocus`, `theme`, `width`, `placeholder`, `style.tokens`, `i18n` и `data` синхронизируются на месте на том же экземпляре; любая другая опция считывается один раз при создании редактора. Он возвращает null, пока редактора не существует (SSR, первый рендер). React принимает вторым аргументом СПИСОК зависимостей `deps`; Vue принимает реактивный источник конфигурации (ref или геттер) и ОДИН `recreateKey` вторым аргументом. Эквивалент в Angular — директива `[blokContent]` (`BlokContentDirective`), которая строит экземпляр в своём собственном хост-элементе и отдаёт его через сигнал `instance` / output `(ready)`.

TypeScript

```
import { useBlok, BlokContent } from '@bloklabs/react';
import { Header, Paragraph } from '@bloklabs/core/tools';

export function Editor() {
  const editor = useBlok({
    tools: { paragraph: Paragraph, header: Header },
    readOnly: false,
  });

  return <BlokContent editor={editor} className="my-editor" />;
}
```

### BlokContent

React/Vue component

Точка монтирования для экземпляра, созданного через `useBlok`. Рендерит `<div>` и переносит в него откреплённый holder редактора. Единственный собственный проп: `editor: Blok | null` (`BlokContentProps`) — передайте null до появления экземпляра, и компонент просто отрисует пустой контейнер. В React он к тому же расширяет `React.HTMLAttributes<HTMLDivElement>`, поэтому `className`, `id` и остальное пробрасываются на этот div, а ref пробрасывается на него же. Аналог в Angular — директива `[blokContent]`, которая создаёт экземпляр сама, а не получает его.

TypeScript

```
import { useBlok, BlokContent } from '@bloklabs/react';

const editor = useBlok({ tools });

// `editor` is null until the instance exists — BlokContent handles that
<BlokContent editor={editor} className="prose" />
```

### provideBlok(defaults)

void | EnvironmentProviders

Регистрирует значения по умолчанию для Blok на уровне всего приложения, чтобы каждый редактор внутри наследовал общий реестр инструментов, тему или конфигурацию i18n, а не повторял их для каждого экземпляра. В React это `<BlokProvider defaults={…}>` (плюс `useBlokDefaults()`, чтобы прочитать их обратно), во Vue — `provideBlok(defaults)`, вызванный в `setup` родителя (за ним стоит ключ внедрения `BLOK_DEFAULT_CONFIG`, а для чтения есть `useBlokDefaults()`), в Angular — `provideBlok(defaults)`, возвращающий `EnvironmentProviders` для массива `providers` (за ним стоит токен внедрения `BLOK_DEFAULT_CONFIG`). Правило слияния, одинаковое во всех трёх: заданное значение конфигурации отдельного экземпляра перекрывает значение по умолчанию, КРОМЕ `tools`, где два реестра сливаются — общий реестр складывается с добавлениями конкретного экземпляра, а не заменяется ими.

TypeScript

```
// React
import { BlokProvider } from '@bloklabs/react';

<BlokProvider defaults={{ theme: 'dark', tools: sharedTools }}>
  <App />
</BlokProvider>

// Vue — inside a parent component's setup()
import { provideBlok } from '@bloklabs/vue';
provideBlok({ theme: 'dark', tools: sharedTools });

// Angular
import { provideBlok } from '@bloklabs/angular';
bootstrapApplication(AppComponent, {
  providers: [provideBlok({ theme: 'dark', tools: sharedTools })],
});
```

TypeScript

```
import { useState } from 'react';
import { BlokEditor } from '@bloklabs/react';
import { Header, Paragraph, List } from '@bloklabs/core/tools';
import type { OutputData } from '@bloklabs/core';

export function Editor() {
  const [data, setData] = useState<OutputData>();

  // data + onSave form a controlled component: onSave fires (debounced)
  // with the serialized document; echoing it back is deduped and
  // caret-stable, while genuine external data changes re-render in place.
  return (
    <BlokEditor
      tools={{ paragraph: Paragraph, header: Header, list: List }}
      data={data}
      onSave={setData}
      theme="auto"
      className="my-editor"
    />
  );
}
```

## Компонент BlokEditor

| Свойство | Описание |
| --- | --- |
| `tools` | `Record<string, ToolConstructable | ToolSettings>` | Регистрируемые блочные инструменты. Только React: функции в любом месте конфигурации инструмента (например, колбэк загрузчика) автоматически перепривязываются к последнему рендеру, поэтому инлайновые замыкания безопасны, и запись в `deps` нужна только при смене КЛАССА инструмента. У Vue и Angular аналога нет — замыкание в конфигурации инструмента захватывается при создании редактора и устаревает, поэтому держите его в стабильном ref/поле либо форсируйте пересборку сменой `recreateKey`. |
| `data` | `OutputData | LooseOutputData | null` | Содержимое редактора (реактивное). Задаёт начальный документ; после монтирования новое содержимое — включая переходы к пустому документу и обратно — перерисовывается на месте на том же экземпляре (редактор никогда не пересоздаётся). Обновления дедуплицируются той же структурной проверкой, что и `equalsOutputData`, поэтому возврат собственного вывода редактора никогда не сбивает курсор — даже если слой хранения его обрезал (новые `time`/`version`, потерянные id и отсутствие метки `lastEditedAt` всё равно считаются отсутствием изменений). Императивные вызовы живут в том же мире: `useBlokHandle().clear()` / `.render()` в React и `BlokEditorComponent.render()` в Angular обновляют этот базовый снимок сразу после выполнения, поэтому возврат `data` к документу, который редактор сам же и выдал, приводит к перерисовке, а не отбрасывается как эхо. Документ целиком, равный `null`, — это контролируемое значение «очистить до пустого» (при собственном вызове render() пропускайте его через `toRenderableData`), а нестрогие backend-DTO принимаются как есть. Angular расширяет тип до `… | undefined`; проп Vue объявлен как `PropType<OutputData>` и является узким исключением. |
| `onSave` | `(data: OutputData, api: API) => void` | Выходная половина контролируемого компонента: срабатывает (с дебаунсом) с полным сериализованным документом при каждом изменении содержимого — вручную опрашивать save() не нужно. Связка onSave={setData} безопасна и не зацикливается. Арность `(data, api)` — это React, где проп передаётся прямо в конфигурацию ядра. Vue отображает его на эмит `save`, а Angular — на output `save`, и оба несут только `OutputData`: `@save="(data) => …"` / `(save)="…"` — либо используйте `v-model:data` / `[(data)]`, за которыми стоят эмит `update:data` во Vue и output `dataChange` в Angular. |
| `onChange` | `(api: API, event: BlockMutationEvent | BlockMutationEvent[]) => void` | Низкоуровневые события мутаций (блок добавлен/изменён/перемещён/удалён) — когда нужна гранулярность отдельных мутаций, а не сериализованный вывод. Пакет мутаций приходит МАССИВОМ, поэтому проверяйте `Array.isArray(event)` перед чтением `event.detail`. Два позиционных аргумента — это арность React; эмит `change` во Vue и output `change` в Angular отдают вместо этого ОДИН объект — `@change="({ api, event }) => …"` / `(change)="…"` с `$event.api` и `$event.event`. |
| `onReady` | `(editor: Blok) => void` | Вызывается с живым экземпляром Blok ровно один раз на экземпляр редактора. Срабатывает после фиксации пробрасываемого ref, поэтому ref.current к этому моменту уже заполнен. Редактор пересоздаётся (и onReady срабатывает снова), только когда меняются deps/recreateKey или компонент перемонтируется — изменения data, включая переходы к пустому документу и обратно, перерисовываются на месте и никогда его не вызывают повторно. Во Vue и Angular это эмит/output `ready` (`@ready` / `(ready)`). |
| `deps / recreateKey` | `DependencyList (React) | unknown (Vue, Angular)` | Значения, при смене идентичности которых редактор уничтожается и создаётся заново (для структурной конфигурации вроде классов инструментов). React принимает массив — `deps` — и пересоздаёт редактор при смене идентичности любого элемента. Vue (`:recreate-key`) и Angular ([recreateKey]) принимают вместо этого ОДНО значение и пересоздают редактор при смене его идентичности; передавайте новый литерал объекта/массива или увеличенный счётчик. `deps` во Vue и Angular не существует. Держите каждое значение референциально стабильным. Функции внутри конфигурации инструментов сюда НЕ входят в React — они автоматически перепривязываются к последнему рендеру. |
| `readOnly` | `boolean | ReadOnlyModeConfig` | Режим «только чтение». Реактивный: после монтирования переключается на месте, без перемонтирования. |
| `theme` | `'light' | 'dark' | 'auto'` | Цветовая тема (реактивная). Не оборачивайте компонент в styled() или HOC, резервирующий проп theme — он не дойдёт до редактора. |
| `onThemeChange` | `(resolvedTheme: 'light' | 'dark') => void` | Вызывается с разрешённой темой при каждом её изменении (например, когда 'auto' следует за ОС). Во Vue и Angular это эмит `theme-change` / output `themeChange` (`@theme-change` / `(themeChange)`). |
| `width` | `'narrow' | 'full'` | Режим ширины содержимого (реактивный). После монтирования синхронизируется через editor.width.set(). |
| `style` | `BlokConfig['style']` | Конфигурация стилей. `style.tokens` реактивен: изменённые переопределения `--blok-*` синхронизируются на месте после монтирования через editor.tokens.set() (с дедупликацией по глубокому сравнению), поэтому переключателю светлой/тёмной темы на стороне хоста перемонтирование не нужно. Семантика замены — передавайте палитру целиком; токены, убранные из неё, перестают применяться. У Angular входа `style` нет: он предоставляет только `style.tokens` — как отдельный вход `[styleTokens]` (`Record<string, string>`). Остальные ключи `style` — `fontSize`, `contentAlign`, `nativeSelection` — задаются через запасной вход Angular `[config]`. |
| `i18n` | `BlokConfig['i18n']` | Конфигурация интернационализации (реактивная). Изменённые `locale`, `messages` или `direction` синхронизируются на месте после монтирования через editor.i18n.update() (с дедупликацией по глубокому сравнению), поэтому переключатель языка меняет подписи редактора без перемонтирования — курсор, фокус, выделение и история отмен сохраняются. Исключение — `defaultLocale`: он читается только при создании. В Angular это вход [i18n]. |
| `locale` | `string` | Только React. Нейтральное к библиотекам сокращение BCP-47 для `i18n.locale`: значение вкладывается в конфигурацию i18n и применяется на месте через editor.i18n.update({ locale }), поэтому переключение языка сохраняет курсор, фокус и историю отмен. При одновременном указании оно ПОБЕЖДАЕТ `i18n.locale`. Используйте его вместе с `getDirection` / `normalizeLocale`, реэкспортируемыми из @bloklabs/react, чтобы самостоятельно вычислять `dir` и проверять теги. Во Vue и Angular такого пропа нет — передавайте локаль внутри пропа/входа `i18n`. |
| `autofocus` | `boolean` | Сфокусировать редактор после монтирования. |
| `placeholder` | `string | false` | Плейсхолдер, который получает каждый блок инструмента по умолчанию, — не только первый блок; со встроенным параграфом он показывается, пока блок пуст и в фокусе. Что именно `false` отключает (и чего не отключает), см. в таблице «Конфигурация», а Placeholder API позволяет менять его на лету через editor.placeholder.set(). |
| `onBlocksRendered` | `(payload: BlocksRenderedPayload) => void` | Вызывается после завершения пакетного рендера (событие ядра blocks:rendered) — декларативный аналог editor.on('blocks:rendered', …). Во Vue и Angular это эмит `blocks-rendered` / output `blocksRendered`. |
| `onBlockRendered` | `(payload: BlockRenderedPayload) => void` | Вызывается для каждого блока, отрендеренного в DOM (событие ядра block:rendered). Во Vue и Angular это эмит `block-rendered` / output `blockRendered`. |
| `ref` | `Ref<Blok | null>` | Пробрасывается к живому экземпляру Blok для императивных вызовов (save, render, blocks, caret, …). Равен null до монтирования редактора, поэтому вызовы должны проверять ref.current. Если содержимое также задаётся пропом `data`, для clear()/render() предпочитайте хендл `useBlokHandle()` из @bloklabs/react: он обновляет контролируемый базовый снимок, тогда как прямой вызов ref.current.render()/clear() меняет содержимое в обход адаптера — и следующее значение `data`, равное ранее выданному редактором документу, будет отброшено как эхо. |
| `className, id, …` | `HTMLAttributes<HTMLDivElement>` | Любой проп, не являющийся опцией конфигурации редактора, пробрасывается на контейнерный div. Стилизуйте редактор через className (style сохраняет своё значение из конфигурации). |
