Editor.js bindings

Has anyone tried to implement bindings for editorjs https://editorjs.io/
It seems that it provides an array of clean json data…
What is the best appropriate YType ? Ymaps? Yarray?
Yarray of subdocuments?
How to deal with cursor position in a multiuser instance?

I’m not aware of any editorjs binding.

If you want to write an editor binding, you want to model the editor data model closely using Yjs types. If it’s just JSON, simply use Y.Array, Y.Map, and Y.Text. If it’s more complex you should look into the Y.Xml* types. They can represent information more densely.

some WIP Collaborative editing based on yjs · Issue #1155 · codex-team/editor.js · GitHub

1 Like

I got something seems to work, feedback welcome.

hi, @Fada

I have a simple idea here, which may be helpful to realize the binding you said.


When constructing an EditorJS instance, it can specify the existing content by passing a parameter named data.


Local to remote

When the editor’s content needs to be persisted to some place through YJS (usually in its onChange function), the latest version of the current editor can be obtained through the member method save of the EditorJS instance.

Remote to local

After the remote data changes are broadcast locally, we can apply the changes locally through EditorJS’
blocks API.

These blocks APIs can help us deal with block-level additions, deletions, and modifications.

For the internal changes of a single block, we need to decide which yType to use to build the content according to the specific block type. For example, for a block of paragraph type, we usually use yText to build its content. At this time, we need to differentiate the content of each block to ensure that only the changed part is applied.


Since the editor’s contents are displayed in the format of native JSON, and we need to persist them to somewhere through YJS, we need to create a converter to convert them (JSON to YType)

My personal suggestion is that the entire editor’s content is an independent yDoc, and a yArray is created at its root, named blocks. Each item is a yMap, which stores the content or pointer of a specific block.

1 Like

thxs @jarone for your advice. My first step is to sync all editorjs content as an Ymap and use a deep observer. But i have an issue with some editorjs plugins that throw every second an onChenge event , see

Another question :
if i use
import { WebrtcProvider } from ‘y-webrtc’
import { WebsocketProvider } from ‘y-websocket’
import { IndexeddbPersistence } from ‘y-indexeddb’

how is prioritized the data ? how to be sure to get data in the IndexeddbPersistance before the remote providers ?
How to do the app has not received data from remote but there is data in indexedDB ?
what is prioritaire ? Webrtc or web socket ?

Because, sometimes (/ often) the user had made a page and it is overwritten by a “undefined” remote data and local data is lost in profit of an empty ?
I would like to send local data to remote instead.

here is my code

with the app

You could listen for the synced event before you establish a websocket connection.

yindexeddb.on('synced', () => {
  new WebsocketProvider(ydoc, ...)
1 Like

Thxs … I will try. Is there a way to know where the data come from?

Yes, you can use transaction origins. I’ve been cooking up a new documentation website. Very early stages, but I think the section about transactions could be useful to you: Transactions | Yjs Docs

The transaction origin will be the instance of the y-indexeddb / y-websocket class.

1 Like