Skip to content
FrameworkJavaScript

Build your first Blok editor

Mount Blok, capture some content, and save it as JSON you can store and load back. The full round-trip in five steps.

Last updated Oct 7, 2026Edit this page on GitHub

This is a hands-on walkthrough. By the end you'll have a working editor. You'll have saved its content to JSON and loaded that JSON straight back in. Everything else in Blok is built on that round-trip.

1

Mount the editor

Point Blok at an element on your page and create an instance. Blok bundles no block tools, so register paragraph in the tools map.

The default block resolves to that tool, and without it the first block renders a "This block cannot be displayed" stub instead of an editable line. Once isReady resolves you have a live editor with an empty paragraph waiting for the caret.

TypeScript
import { Blok } from '@bloklabs/core';
import { Paragraph } from '@bloklabs/core/tools';

const editor = new Blok({
  holder: 'editor', // the id of a <div> on your page
  tools: {
    paragraph: Paragraph, // the default block every empty editor starts with
  },
});

await editor.isReady;
2

Write some content

Click in and type. Press Enter to start a new block, or press / to open the tool menu and choose a heading, list, or quote. Every line you create is a separate block.

3

Save it to JSON

Call save() to get your content as a plain object. The structure is typed JSON with no hidden state, only blocks you can store anywhere. Inline formatting is stored in rich text fields as an array of { text, marks } runs.

TypeScript
const data = await editor.save();

console.log(data);
// {
//   time: 1719000000000,
//   blocks: [
//     { id: 'a1b2c3', type: 'paragraph', data: { text: 'Hello, Blok' } },
//   ],
//   version: '1.16.0', // the installed Blok package version
// }

That object is the whole point. It's portable JSON you can drop into a database, a file, or an API. It's exactly what you'll load back next.

4

Load it back

Hand the same object to render() and Blok rebuilds the content exactly. Save on unload, render on load. That is persistence, done.

TypeScript
// On the next page load, hand the same object back:
await editor.render(data);
5

Add a tool

Blok ships lean. It registers no block tools of its own. Register the ones you want under the tools config and they appear in the / menu, ready to use.

Keep paragraph in the map. There is no default set to fall back to, so you have to list every block type you rely on, the default one included.

TypeScript
import { Blok } from '@bloklabs/core';
import { Header, List, Paragraph, Quote } from '@bloklabs/core/tools';

const editor = new Blok({
  holder: 'editor',
  tools: {
    paragraph: Paragraph, // keep the default block registered
    header: Header,
    list: List,
    quote: Quote,
  },
});

Checkpoint: what success looks like

You should now have three things.

  • A live editor on the page.
  • A data object from editor.save() with your blocks inside it.
  • That same object loading cleanly through editor.render().

If all three are true, you have the round-trip. Everything else in Blok builds on it.