Skip to content
FrameworkJavaScript

The Blok class: create and destroy an editor

The main editor class that initializes and manages the Blok editor instance.

Last updated Jun 30, 2026Edit this page on GitHub

Reaching the editor instance

The methods below run on the editor you created with new Blok(). They are available once editor.isReady resolves.

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

Methods

save()

Promise<OutputData>

Extracts the current editor content as structured JSON data. This is the primary method for persisting editor content.

When to use

Call after await editor.isReady. The returned JSON is your source of truth — store it and feed it back to render().

TypeScript
// Save editor content
const data = await editor.save();
console.log(data.blocks); // Array of block data

render(data)

Promise<void>

Renders editor content from previously saved JSON data. Accepts the loose wire shape (`LooseOutputData`) — `null` values for block `data`, `id`, or `time` from backend DTOs are normalized at the boundary.

When to use

Loads saved content and replaces the current document. To append instead of replace, use blocks.insertMany().

TypeScript
// Load saved content
const savedData = {
  blocks: [
    { id: '1', type: 'paragraph', data: { text: 'Hello' } }
  ]
};
await editor.render(savedData);

focus(atEnd?)

boolean

Sets focus to the editor. Optionally positions cursor at the end of content.

When to use

Pass true to place the caret at the very end. For a specific block or offset, use the caret API instead.

TypeScript
// Focus at start
editor.focus();

// Focus at end
editor.focus(true);

clear()

Promise<void>

Removes all blocks from the editor.

When to use

Wipes all blocks and leaves one empty paragraph. It's undoable — unlike destroy(), which tears the instance down.

TypeScript
// Clear all content
await editor.clear();

destroy()

void

Destroys the editor instance and removes all DOM elements and event listeners.

When to use

Call from your framework's unmount hook to avoid leaked listeners. The instance is unusable afterwards — create a new Blok to start again.

TypeScript
// Clean up on component unmount
editor.destroy();

whenAllReady(options?)

Promise<void>

Static method — resolves once every Blok instance in scope has finished booting (each instance's `isReady` has settled; rejections count as settled). A collective-readiness signal for pages hosting several instances, replacing hand-aggregated per-instance `onReady` callbacks. Pass `within` (an Element) to count only instances mounted inside a subtree you own, so an unrelated editor elsewhere on the page cannot hold your gate closed. Pass `settleOn: 'rendered'` to extend readiness from construction to content-in-the-DOM, which also covers post-boot re-renders from `render(data)`. An empty scope resolves immediately. Instances that appear while the promise is pending extend the wait; instances constructed after it resolves are not covered — call again, or use `subscribeReady()` for a live signal.

When to use

Call it as Blok.whenAllReady() on the class, not on an instance. An instance that is still booting and whose wrapper is not attached to the document yet counts in every scope — over-waiting is safe, under-waiting is a bug.

TypeScript
// A comments list: N read-only bodies + a composer.
// Wait only for the editors inside this list.
await Blok.whenAllReady({
  within: listElement,
  settleOn: 'rendered',
});
composer.focus();

readyState(options?)

{ total: number; pending: number; ready: boolean }

Static method — synchronous readiness snapshot for a scope: how many instances match `within`, how many are still pending at the requested `settleOn` depth, and whether the scope is settled. An empty scope reports `ready: true`, so no "nothing to wait for" special case is needed.

When to use

Cheap enough to call on every notification from subscribeReady(); it walks the registered instances and tests DOM containment.

TypeScript
const { pending, ready } = Blok.readyState({ within: listElement });

if (!ready) {
  showSkeleton(pending);
}

subscribeReady(listener)

() => void

Static method — subscribes to readiness changes across all instances (construction, boot, render-state flip, destroy) and returns an unsubscribe function. The listener takes no arguments: re-read `Blok.readyState(scope)` when it fires. Pairs with `useSyncExternalStore` and other store adapters, giving a live signal instead of a one-shot latch.

When to use

Framework users should prefer the adapter wrappers — useBlokReady() in @bloklabs/react and @bloklabs/vue, injectBlokReady() in @bloklabs/angular — which wrap this subscription and the scope lookup.

TypeScript
const unsubscribe = Blok.subscribeReady(() => {
  setReady(Blok.readyState({ within: listElement }).ready);
});

// later
unsubscribe();

Properties

PropertyTypeDescription
isReadyPromise<Blok>Promise that resolves with the ready editor instance
isRenderedbooleanSynchronous render-readiness flag — true once the current render batch has landed in the DOM (mirrors the `data-blok-rendered` wrapper attribute); false before the first render and while a re-render is in flight. Complements the async `isReady`/`onReady`: no await or callback needed, so mount state can be polled synchronously.
blocksBlocksBlocks API module
caretCaretCaret API module
historyHistoryHistory API module
saverSaverSaver API module
toolbarToolbarToolbar API module
inlineToolbarInlineToolbarInline toolbar API module