---
title: "Editor.js for Retool: an open-source block editor component"
description: "Block-style editing in Retool, free to use and extend."
canonical: "https://stackdrop.co/blog/editor-js-retool-component"
published: "2026-05-19T09:00:00.000Z"
updated: "2026-05-19T09:00:00.000Z"
authors: ["Vaggelis Kapetanakis"]
topics: ["Retool"]
readers: ["builders"]
---

# Editor.js for Retool: an open-source block editor component

The knowledge base team writes articles inside a Retool app, and the website renders them. A plain text area loses headings and lists. An HTML field keeps them, and every downstream system then has to parse, clean, and sanitize markup before it can use the content. What the team needs is rich text stored as structured data.

Editor.js does that. It is a block-style editor whose output is JSON: one object per heading, paragraph, list, or quote. We packaged it as a Retool custom component, written in TypeScript, and published it on [GitHub](https://github.com/StackdropCO/editorjs-retool-component) under the MIT license, free to use and extend.

## What it does

- **Block editing.** Headings (H1 to H4), paragraphs, ordered and unordered lists, quotes, code blocks, checklists, tables, delimiters, and warnings.
- **Inline formatting.** Marker, underline, inline code, links, and footnotes.
- **Embeds.** YouTube and CodePen.
- **JSON output.** The `content` property holds the editor's state as a JSON string.
- **Tool switches.** Each tool can be turned on or off in the inspector.
- **Styling.** `backgroundColor` (default `#f8fafc`) and `textColor` (default `#000`).

## Install and deploy

You need Node.js 20 or later and an API access token with read and write scopes for Custom Component Libraries.

```bash
git clone https://github.com/StackdropCO/editorjs-retool-component.git
cd editorjs-retool-component
npm install
```

Log in, create the component library in your Retool organization, and start development mode:

```bash
npx retool-ccl login
npx retool-ccl init
npx retool-ccl dev
```

When it is ready, deploy an immutable version:

```bash
npx retool-ccl deploy
```

Then open the Custom Component settings in your app and switch from dev to the version you just published. You may need to refresh the page before the new version appears.

## Load and save content

Drag the Editor.js component onto the canvas. The `content` property works in both directions. Set it to load existing content, and read it to save what the user wrote. The component updates `content` as the user types.

In the examples below, the component is named `editor1` and the content lives in a Postgres `jsonb` column. A query loads the selected article:

```sql
select body
from knowledge_articles
where id = {{ articlesTable.selectedRow.id }};
```

Bind `content` to that result, as a string:

```javascript
{{ JSON.stringify(getArticle.data.body[0]) }}
```

A Save button runs the write query. Retool sends `{{ }}` values in a SQL query as prepared statement parameters, so the JSON arrives as one value:

```sql
update knowledge_articles
set body = {{ editor1.content }}::jsonb,
    updated_at = now()
where id = {{ articlesTable.selectedRow.id }};
```

For a new article, bind `content` to a temporary state variable instead, and insert on save.

## What the data looks like

Each save stores a document like this one:

```json
{
  "time": 1635603431943,
  "blocks": [
    {
      "id": "12345",
      "type": "header",
      "data": {
        "text": "Editor.js",
        "level": 2
      }
    },
    {
      "id": "67890",
      "type": "paragraph",
      "data": {
        "text": "This is a paragraph block."
      }
    }
  ],
  "version": "2.23.2"
}
```

Because every block has a type and its own data, the content is easy to query, version, and render elsewhere. A website can map `header` blocks to its own heading styles, with no HTML cleanup in between.

## Limit the tools

Every tool has a switch in the inspector: `enableHeader`, `enableList`, `enableQuote`, `enableChecklist`, `enableCode`, `enableInlineCode`, `enableMarker`, `enableDelimiter`, `enableEmbed`, `enableTable`, `enableWarning`, `enableLink`, `enableUnderline`, and `enableFootnotes`.

Turn on only what the content needs. A knowledge base might allow headings, paragraphs, lists, and links, and nothing else. A smaller tool set keeps the editor simple for authors and the stored content consistent.

## Running it in production

- **Version the content schema.** Editor.js writes its version into every document. If you change the tool set later, plan a migration for older block types.
- **Sanitize when you render.** The JSON is structured, and embedded content can still carry markup. Sanitize on the way to HTML, especially for embeds.
- **Keep the JSON as the source.** If a fast front end needs HTML, render and cache it. The JSON stays the version you edit.
- **Add a preview.** A panel that renders the blocks lets authors see the result before publishing.
- **Convert where consumers need it.** If another system expects HTML or markdown, add a converter from the block JSON. Libraries exist for both.
- **Guard against empty saves.** Before the update runs, check that the parsed `content` has at least one block, in the Save button's event handler. A blank editor should never overwrite an article:

```javascript
// "Only run when" on the Save button's click handler
{{ JSON.parse(editor1.content || '{}').blocks?.length > 0 }}
```

- **Pin a published version.** Production apps should never point at the dev version of the library.

## What is next

On the roadmap, not committed:

- Drag-and-drop block reordering.
- Custom block types configured from the inspector, such as a callout box or an embedded chart.
- A full-screen editing mode.
- Starter templates for blog posts and knowledge base articles.
- A companion component that renders the JSON for preview.

## Our view

We recommend storing rich text as Editor.js JSON when more than one system reads the content, because each reader can render blocks its own way. For a single internal note field, Retool's built-in Rich Text Editor is simpler, because it needs no library to deploy or maintain.

Issues and pull requests are welcome. For AI-assisted writing inside an app, see our [AI rich text editor component](https://stackdrop.co/blog/ai-rich-text-editor-retool-component). [What is a custom Retool component](https://stackdrop.co/blog/what-is-a-custom-retool-component) covers when building one is worth it.
