⌨️ Rich-Text Editor
TipTap
To provide a good editing experience, we looked at a variety of Rich-Text Editors to find out which one works best for us and ended up settling on TipTap. TipTap is based on ProseMirror but makes it a lot more accessible in terms of customization. Through the extensions provided by TipTap, you can easily add or remove features from the editor in the extensions property of the editor.
TipTap in WebEdit
Our editor component can be found under /apps/dashboard/src/components/Editor. In here you will find a couple of files.
- Control.tsx - A button component that handles active states of the Toolbar buttons.
- Plaintext.tsx - A Plain-Text version of the TipTap editor.
- Toolbar.tsx - The Toolbar for the Rich-Text editor.
- index.css - Styling for all the Marks and Nodes used in the editor.
- index.tsx - Rich-Text editor component.
- utils.ts - Functions used in any of the above components.
Adding New Features
Though our Editor already provides a variety of features, there are still more that can be implemented through unused TipTaps Extensions or custom ones.
Adding Existing Features
Implementing features that already have a TipTap extension is quite simple. You find the feature you want to implement, download the package, add it to the extensions property, and you’re basically done. The editor now supports that feature; however, in most cases, you will need to add some styling to make the features visible in the editor.
Adding Custom Features
TipTap allows for a lot of customization, even to its already existing extensions. A overview on how this can be done is shown here in the TipTap documentation.
import { Extension } from '@tiptap/core'
const CustomExtension = Extension.create({ // Your code here})
const editor = new Editor({ extensions: [ // Register your custom extension with the editor. CustomExtension, // … and don’t forget all other extensions. Document, Paragraph, Text, // … ],})
Features Overview
Nodes
Extension Name | In Use? |
---|---|
Blockquote | Yes |
Bullet list | Yes |
Code block | Yes |
Code block lowlight | No |
Document | Yes |
Hard break | Yes |
Heading | Yes |
Horizontal rule | Yes |
Image | Yes |
List item | Yes |
Mention | No |
Ordered list | Yes |
Paragraph | Yes |
Table + -cell, -row, -header | Yes |
Task list + -item | Yes |
Text | Yes |
Youtube | Yes |
Marks
Extension Name | In Use? |
---|---|
Bold | Yes |
Code | Yes |
Highlight | No |
Italic | Yes |
Link | Yes |
Strike | Yes |
Subscript | Yes |
Superscript | Yes |
Text style | No |
Underline | Yes |
Functionality
Extension Name | In Use? |
---|---|
Bubble menu | No |
Character count | Yes |
Collaboration | Yes |
Collaboration cursor | Yes |
Color | No |
Dropcursor | Yes |
Floating menu | No |
Focus | No |
Font family | No |
Gap cursor | Yes |
List keymap | No |
Placeholder | Yes |
Starter kit | No |
Text align | Yes |
Typography | No |
Undo & Redo History | No |
Future Work
Originally we decided on a different editor called Lexical that is made by Meta. However after trying to implement the Yjs binding through the given package we found out that the binding doesn’t work at the time. If the binding gets fixed we could see a migration to Lexical.