Choice of editor

Hello all,

In this proposal I’d like to discuss the choice of the editor for Cristal.

Detailed analysis can be found in the Rich Editor / Realtime Editing design page.

The list of good quality and maintained (not that all the editors are maintained by a small group of 1 or 2 active committers) editors is:

  • quill
  • TipTap
  • Prosemirror
  • Editor.js

Differencing criteria:

  • Abstract Document Model: It is important for the framework to provide an abstract document model, decoupled from the actual html of the editor. This abstract document model must also be extensible to be able to define custom elements (e.g., macros).
  • Availability of good-looking editor plugins (e.g., image, block, quick actions…). This point is important as we are wiki developers and not editor developers. Therefore, we need to minimize the editor development work to integration and customization of existing UI elements, and not on the development of editor UI elements
  • Realtime support: there is no out of the box realtime support for any editor, but we can’t select one where reatime integration is know to be difficult
Editor Abstract document model Nice editor plugins Existing Realtime implementation Comments
Quill yes Good looking but closer to CKEditor (i.e., no quick actions or block drag handles)
Missing features such as image aligmnent.
yes Version 2 not still officially stable, but should be in the near future
TipTap yes since based on Prosemirror A nice set of available extensions, though not as rich as we’d like, for instance no support for image with captions currently, and the classic block editing left hand side handle to move block is a paying extensions yes
Prosemirror yes Very minimal set of available extensions. Prosemirror is a very good technical base to build editors (milkdown, or tiptap are build on top of it), but it does not come with good-looking UI elements. yes
Editor.js yes, but missing essential operations for realtime implementation - Quick actions out of the box
- block drag handles out of the box
no

Conclusion:
We are in the difficult situation where there is no clear winner and we’ll need to focus our works.

  • Editor.js is not an option as the realtime support seems to be very poor, which is a shame as this is imo the most good looking option and a really good out of the box editor (when one don’t need customization)
  • Prosemirror is a very strong choice allowing use a good access to low level APIs. This can come handy when working on retro-compatibility with exiting XWiki pages or the support for advanced macro features. On the other hand, the available plugins are not very good looking and we’ll probably need to rework there design, and possible extend them to add missing features
  • TipTap is a good choice as well as it’s based on Prosemirror. The cons being:
    • payed model, most of the interesting/advanced UI elements are pro and need a license (with the risk of seeing more UI elements becoming pros over time)
    • by limiting ourselves to the free UI elements, we are close to when Prosemirror is offering but with an additional TipTip specific layout that could be cumbersome for advanced customization
  • Quill is also a good choice with a version 2.0 in alpha. But the editing experience is more “traditional” (i.e., no notion of block, or no quick action available out of the box). In addition: existing plugins are often only compatible with Quill 1.x

My feeling is that quill will be a good choice in about a year once v2.0.0 will be stabilized.
In the meantime, I’m +1 for prosemirror as it checks all technical requirements except for the availability of nice UI elements. Note that while
I’m +0 for TipTap as I’m afraid that their business model could bite us in the feature with extensions becoming non-free in the future.

WDYT?

Wouldn’t one option be to use our own realtime since we have it? If that’s the only downside, isn’t that a good option?

when one don’t need customization

Maybe that’s even more important than a missing realtime feature, no? While we could provide the realtime feature, maybe Editor.js wouldn’t be customizable enough for our needs?

Thanks

The issue is not really the realtime server we use but how to apply the changes on the editor. From what I can read online, people trying to integrate realtime in editor.js complains about the API limiting them in what they can do. For instance:

Also, this is the only editor for which I couldn’t find at least a tutorial or a proprietary realtime solution. I read it as a proof that using editor.js for realtime is overly complex.
Maybe @mflorea has something to say about this though?

I agree. Digging further editor.js seems more customizable that I initially though but:

  1. I feel like documentation is not as good and easy to find as for prosemirror
  2. The ecosystem lacks features we would like. For instance, the markdown parser library is unmaintained, and that’s something we’d like to have out of the box.

Combined with the realtime limitations, I stay -1 on editor.js

Being able to update the edited content incrementally is critical for real-time. For CKEditor 4 we have access to the DOM so we can patch it, but then we need to make sure we don’t break any references that CKEditor keeps to the DOM (e.g. in CKEditor widgets that are used to integrate rendering macros). If Editor.js doesn’t provide (safe) access to the DOM and neither has an API to update the edited blocks incrementally then it’s a no-go. The links that Manuel gave are worrying indeed.

There is something I don’t understand though: you said Editor.js doesn’t have an abstract document model but at the same time I’ve seen mentions of a Block API. Are those blocks exposing the DOM directly?

Thanks,
Marius

ok, reading the discussions it seems that editor.js does have a block API (see snippet below, for 3 simple blocks containing aaa, bbb, and ccc).
But, this block API is missing operation for efficient diff and re-rendering of changes only. Those being essential to have good realtime implementation.

{
  "time": 1713346848334,
  "blocks": [
    {
      "id": "9qDQfvR7D3",
      "type": "paragraph",
      "data": {
        "text": "aaa"
      }
    },
    {
      "id": "fve7dwmlak",
      "type": "paragraph",
      "data": {
        "text": "bbb"
      }
    },
    {
      "id": "D2P95iJnZm",
      "type": "paragraph",
      "data": {
        "text": "ccc"
      }
    }
  ],
  "version": "2.29.1"
}

My take from all the discussions and also my own analysis:

  • prosemirror based sounds the most reasonable approach. Others have had success with it. Multiple editors on it
  • yjs is a good solution for realtime (good user base). My understanding is that the way it’s implemented is serious and flexible (used in many cases)

Going for a implementation that is known to work well with Markdown makes sense to me. I know Milkdown does that as a main output (not sure why it’s not in the shortlist, is it because it’s single dev ?), but maybe they are too tight to markdown. TipTap seems to have a markdown export plugin. Not sure were markdown is in their system.

As far as I understand both TipTap and Milkdown use yjs for realtime.

If there is a good reason to eliminate Milkdown, from what I see TipTap would be a good place to start, with the risk that somehow it changes business model or closes some extensions. In that case it would be like being on our own on Prosemirror. In that case it’s better to be there with a good initial implementation instead of doing our own

So I’m +1 for TipTap.

Yes, Milkdown being heavily focused on Markdown makes me afraid that we won’t be able to support other syntaxes in the future.

Maybe not exactly, they seem to be providing some sort of wrapper on top of prosemirror, but are still giving access to prosemirror through a @tiptap/pm package.

Also, after starting to really work with prosemirror, I realized that the available plugins are quite basic and/or unmaintained, and a huge amount of work would be needed to implement the basic editing operations.

So even though Tiptap is a risk regarding their business model, I’m now +1 to take the risk and start from Tiptap.
And I’m changing my vote to +0 for prosemirror for the reasons explained above.

Note: I have successfully integrated Tiptap in Cristal, with a basic quick action (/) integration.
I believe this is a good proof that Tiptap is a good fit for us and that we can pursue with that choice.
If nobody objects, I’ll mark this discussion as solved and document our choice of Tiptap for the editor.