HTML wysiwyg editor bindings

I’m looking into using YJS with a drag-and-drop page builder like grapesjs or https://github.com/givanz/VvvebJs

But I’m not really sure where to start. I’m wondering do I need to build a custom binding like yjs-monaco, yjs-prosemirror, or yjs-quill? I looked at those bindings for ideas, but frankly they’re all way above my pay grade. Any help at all would be greatly appreciated.

Would Y.XmlElement even play nicely with a drag-and-drop editor that spits out HTML? Would I have to diff the HTML to get the insert and delete operations? Any help at all would be amazing. Thank you!

TIL that the prosemirror plugin actually uses Y.XmlFragment already, so that could be a nice place to start. It seems like each integration is very library-specific, but I’m trying to figure out what they have in common and how to make one for a new library

Hi @mcmar that sounds like a really interesting application for Yjs!

The idea of a data binding with Yjs is that you try to represent the model of your application with Yjs types. If the Yjs types changes you need to update the binding target, and vice versa. ProseMirror and Quill have data models that don’t directly translate to Yjs types. They support formatting attributes on text (e.g. bold, italic) that need to be represented efficiently in Yjs. This is why the editor bindings are pretty complicated.

If your application is based on a JSON model, your data binding might be pretty straight forward, because you can represent that simply as Y.Array and Y.Map types. But it is necessary that your binding target has a well-defined data model and fires events when it changes.

I’m not sure if you would want to simply bind to the HTML output. Of course that would be possible because you can simply represent the output as an Y.XmlElement. But I’m not sure if the application would be able to handle it if you just replace the output - I assume that all page builder libraries use some kind of JSON-based internal representation of the state of the application. Although if you go that route, I find it helpful to diff the old with the new state and apply the difference to the Yjs model, instead of manually calculating the insert/delete positions.

As a start, you should begin to research page builders with a proper data model that you can observe and fires events when it changes. Furthermore, you could play with the Yjs types and try to understand how you change and observe them. I documented the Type API here. Now all types also emit a description of the changes (a diff) when they change (checkout event.changes - the changes are represented in a flavor of the Quill delta format). I haven’t put it in the documentation because the API is not yet stable.