Rich Editor / Realtime Editing
Description
This document lists choices and rich editor and realtime editing libraries, as well as choice criteria.
The goal is to gather enough details to be able to make a choice for the replacement of the current CKEditor 4 based editor, as it maintenance stopped.
Realtime editing library is listed here since it is tightly coupled to the editor choice.
Rich Editor
Actions
- narrow down to 2/3 good options
- confirmation with CODIR/Client Team about block editing?
- check compat. with chainpad - PoC
- check compat. with legacy content
- nested block support?
Options
- CKEditor 5
- License issue (GPL)
- Paying services like realtime and not easy to plug XWiki's realtime in it
- TinyMCE
- Used by XWiki in the past, was painful and we got away from it
- Quill
- No releases since 2019, but a 2.0.0 seems to be activally developped (see https://github.com/quilljs/quill/tags)
- Tiptap
- Maintained, based on ProseMirror
- Editor.js
- Block editor
- Maintained
- ProseMirror
- MIT license
- Maintained by a single person but funded by several companies and widely used
- Realtime support using Yjs (MIT)
- Rich ecosystem, e.g., Tiptap or Milkdown or BlockNote (MPL 2.0 license), a block-based editor (without table support for now), building on top of it, or a plugin for inline editable code blocks (ISC license).
- Used by companies like Atlassian (couldn't find an official statement, but they're also listed as sponsor) and prototypes at GitHub. Also available as plugin for DokuWiki.
- Milkdown: https://milkdown.dev/
- Based on ProseMirror, mapping to markdown. Yjs integration.
- Maintained. One person however. Plugin architecture which is interesitng
- Novel: https://github.com/steven-tey/novel Apache (ASL v2)
- BlockSuite: https://github.com/toeverything/blocksuite MPL v2
- Slate: https://github.com/ianstormtaylor/slate
- Gutenberg (wordpress), GPL, planned to change licence but could be a problem.
Criteria
- License
- Support for block editing
- Support for nested blocks
- Allows supporting columns through a column block
- Support for nested blocks
- Maintained
- Compatibility with a realtime editing library
- Support for markup syntaxes (xwiki syntax, markdown)
- Very extensible
- ability to toggle to sources -> actually handled by a custom plugin for CKEditor 4, so we'll probably need to verify that customization features are able to handle something similar
XWiki Customization
Experience from working with CKEditor 4
- Loading
- We have two use-cases: replacing a textarea HTML element (usually inside an HTML form) or editing directly (in-place) an HTML element (e.g. DIV).
- We can provide HTML as input (even though the content is stored as wiki syntax).
- When replacing a textarea HTML element (iframe-based editor) we need to be able to inject CSS and JavaScript. In this case we should have full control over the HTML input document (not just the BODY element that is directly edited).
- We need to be able to configure the editor locale to match XWiki's locale.
- Saving (assuming we keep the explicit save / cancel action instead of automatic save)
- We need to be able to get the HTML output to either update the textarea HTML element on xwiki:actions:beforeSave event or send it to the server side when editing in-place.
- We need to be able to detect if the edited content is dirty (has unsaved changes) and show the leave confirmation.
- We also need to reset the dirty flag on save and cancel actions.
- We need to be able to register keyboard shortcuts for save and cancel.
- Back-Forward Cache
- Using the browser's Back button after an accidental leave of the edit mode should restore the content.
- Content Filtering
- We need to be able to configure the allowed HTML elements and attributes per wiki syntax (e.g. XWiki 2.1 syntax doesn't support attributes on list items).
- We need to be able to filter the HTML (DOM) client-side, before it gets sent to the server for conversion (e.g. convert empty lines to empty paragraphs and back, submit only the significant content, convert deprecated tags like font into span tags with in-line style).
- We need to be able to reload the editor when the document syntax changes (because other filters need to be applied).
- Auto-suggest
- We need some kind of support for implementing auto-suggest inside the editing area (for links, mentions, quick actions). This means for instance being able to register a prefix (e.g. @) that triggers a specific type of suggestions.
- Placeholders
- We need to be able to implement placeholders for empty content (e.g. "Start typing here...") and empty blocks (e.g. "Type / for quick actions...").
- Markers (metadata for links, images and macros)
- We need to be able to include additional hidden information in the HTML (e.g. XML comments) for some wiki syntax elements that can help us re-create the wiki syntax on save (e.g. page reference, attachment reference, macro parameters and content).
- Images
- We need support for captioned images.
- We need to be able to hook our custom image insert and edit dialogs (blocks).
- We need to implement our quick image insertion action (shortcut).
- Links (to wiki pages and attachments)
- We need to be able to hook our custom link insert and edit dialogs (blocks).
- We need to implement our quick link insert action (shortcut).
- Macros
- We need support for read-only areas (blocks) for protecting the macro output.
- We need to be able to hook our macro insert / edit dialogs (blocks).
- We need to be able to reload the editor content on macro insertion.
- We need to support nested macros (blocks) and in-place editable macros.
- Office
- The editor needs to handle paste from Office documents and the pasted content needs to be filtered.
- We need to be able to register additional filters for paste from office.
- We need to be able to hook our custom Office Import dialog (that uses server-side office to HTML conversion).
- Source
- We need to be able to view the source wiki syntax.
- We need to be able to preserve the selection (caret) when switching between WYSIWYG and Source.
- We need to be able to put the editor in loading / read-only mode while the Source conversion takes place.
- Selection
- We need to be able to access the current selection / caret.
- We need to be able to save and restore the selection (before / after some change).
Requirements Checklist
- Support for both iframe and in-place editing
- Localization
- Content dirty detection
- Custom keyboard shortcuts
- Configurable content (HTML) filtering
- Reload / Refresh the editor / content
- Auto-suggest
- Notifications (inside the editor)
- Placeholders
- Metadata / Markers (for links, images and macros)
- Captioned images
- Drag & drop files
- Custom dialogs / blocks
- Custom toolbar buttons / actions
- Balloon toolbar or context menu
- Read-only blocks
- Nested editable areas
- Paste filters
- Loading and read-only editor state
- Source mode
- Selection API, with save and restore
- Emojis
- Dynamic theme with CSS (or LESS) variables
- Full-screen mode
Requirements Matrix
Candidate | Support for both iframe and in-place editing | Localization | Content dirty detection | Custom keyboard shortcuts | Configurable content (HTML) filtering | Reload / Refresh the editor / content | Auto-suggest | Notifications (inside the editor) | Placeholders | Metadata / Markers (for links, images and macros) | Captioned images | Drag & drop files | Custom dialogs / blocks | Custom toolbar buttons / actions | Balloon toolbar or context menu | Read-only blocks | Nested editable areas | Paste filters | Loading and read-only editor state | Source mode | Selection API, with save and restore | Emojis | Dynamic theme with CSS (or LESS) variables | Full-screen mode |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Prosemirror | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
The same is true for content pasting. | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
Comparison Matrix
Options | Acceptability | License | Github | Maintainer | Maintained | Support for block editing | Native Data Storage (html,json,markdown,...) | Toggle to source mode | Compat. with yjs | Compat. with chainpad | Support for XWiki Syntax | Comments |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Editor.js | Apache 2 | https://github.com/codex-team/editor.js | Developed by https://codex.so/
| Last release: Aug 24 2023 | ![]() | ![]() | A hackathon was done with the editor on 2022. | |||||
TinyMCE |
| MIT | https://github.com/tinymce/tinymce | Last release: Nov 15 2023 (see release note) | ![]() | ![]() | ||||||
Tiptap | ![]() | MIT | https://github.com/ueberdosis/tiptap | ![]() | Last release: Nov 30 2023 | ![]() | ![]() | Provides a lot of plugins and a Vue components. But seems to be quite "enterprise" oriented which could increase the chances to end-up with the same model as CKE4. | ||||
ProseMirror | ![]() | MIT | https://github.com/ProseMirror/prosemirror | ![]() But, used as framework by several other projects (e.g., tiptap, or outline) that are interested in seeing the project continue. | Last release: Dec 4 2023 (see the release notes) | ![]() | ![]() | Either by following the same strategy as we do for CKEditor 4. The editor manipulates html, and the conversion to xwiki/2.1 is done through a remote endpoint. Or, we can also introduce native support client side for xwiki/2.1 (same as https://github.com/ProseMirror/prosemirror-markdown) but that's a lot of work. | Propose a lot of plugins, a lot of them being community maintained. | |||
milkdown | ![]() | MIT | https://github.com/Milkdown/milkdown | ![]() | Last release: Nov 23 2023 | ![]() | ![]() | |||||
novel | ![]() | Apache 2 | https://github.com/steven-tey/novel | Last release: Oct 3 2023 | ![]() | ![]() | ||||||
Gutenberg | ![]() | GPL/MPL | https://github.com/WordPress/gutenberg | Last release: Dec 1 2023 | ![]() | ![]() | ||||||
CKEditor 5 | ![]() | GPL2 | https://github.com/ckeditor/ckeditor5 | CKEditor developers | Last release: Nov 15 2023 | ![]() | ![]() | |||||
Quill | ![]() | BSD 3 | https://github.com/quilljs/quill | ![]() | ![]() | ![]() | ||||||
blocksuite | ![]() | MPL 2.0 | https://github.com/toeverything/blocksuite | Last release: Nov 27 2023
| ![]() | ![]() | ||||||
BlockNote | ![]() | MPL 2.0 | https://github.com/TypeCellOS/BlockNote | ![]() | 0.12.4 on Apr. 2024 | ![]() | Also based on prosemirror! | |||||
liveblocks | ![]() |