Lexical React Guide
This document provides additional information for developers in using codox to add collaboration and multi-player capability in Lexical under the React framework
Comment Threads
For enhanced asynchronous collaboration, the CodoxCommentPlugin
allows users to interact via threaded comments directly within the document. This plugin is inspired by the Lexical playground’s CommentPlugin
and has been adapted to integrate directly with both Codox and Lexical frameworks.
To integrate the comment plugin into your Lexical application, include it within the LexicalComposer
component like so:
This setup allows the comment threads to become a part of the application state that Codox synchronizes across all active users. As users create new comment threads or comments, or delete existing ones, these actions are reflected in real-time across all sessions.
Initializing Comment Threads
Before you start a Codox session, it’s important to preload any existing comment threads associated with the document. This ensures that when users join the session, they have immediate access to all historical comments. To integrate this functionality, you can extend the existing startCodox
function to include an initialization step for comment threads:
In this configuration, the commentsThread
is assumed to be part of the initLexicalState
. However, it’s not mandatory for it to be stored within this state. You can adapt this setup depending on where and how you store your application’s state related to comments. This approach not only ensures the continuity of the discussion threads but also enhances the collaborative experience by maintaining the context of conversations.
Persisting Thread
Codox is not strongly opinionated about how and where comment threads are persisted with the app’s
architecture. We do however expect that any existing comment state be retrieved and made visible to
codox via the initComments
api call, and any changes to the comments will be saved.
When threads are created, delete, or updated (i.e. new comments added/old comments deleted),
codox will notify the changes by invoking the contentChanged
hook callback (if supplied) and
emit the content_changed
event. The developer will then decide what to do with the comments, for instance
persisting the comment in the backend:
The content
parameter of the callback includes both the document’s root content and the commentThreads
array:
State Representation
Threaded comments are represented as an array where each element is a single thread identified by a codoxId
. Comments within a thread are stored in an array, with each comment comprising content
, author
, timestamp
, and codoxId
:
Comments UX
The plugin includes a default user interface that displays comment threads attached to the document. This UI is typically positioned to the right-hand side of the page. Through this interface, users can respond to or delete comments.
To initiate a new comment thread, the editor.dispatchCommand(INSERT_COMMENT)
command is used, typically triggered when a user selects a portion of the text. The exact mechanism for triggering this through the UI depends on the specific design choices made by the application developer. When this command is issued, the CodoxCommentPlugin
presents a text field or dialog adjacent to the highlighted text, where the user can enter the initial comment for the thread. We demonstrate how to implement this feature with a floating menu bar in our Extend Demo.
Validating Node Nestings
In Lexical, there is no inherent enforcement of specific nesting combinations of native and third-party nodes. This flexibility can sometimes result in document corruption, where the document becomes unmanageable by plugins or core code, or the content is rendered incorrectly.
To prevent such issues, we have established a set of rules that restrict certain node nesting combinations. The table below details these prohibitions. For example, the first row specifies that a table node cannot be nested within another table, image, inline-image, or sticky node. The last line specifies that the Excalidraw plugin should not be inserted into the caption section of an image, inline-image, or sticky note.
Target (child lexical node types) | Invalid Parents Nodes (to insert into) |
---|---|
“table” | “table”, “image”, “inline-image”, “sticky” |
“image” | “image”, “inline-image”, “sticky” |
“horizontalrule” | “table”, “image”, “inline-image”, “sticky” |
“page-break” | “table”, “image”, “inline-image”, “sticky” |
“collapsible-container” | “table”, “image”, “inline-image”, “sticky”, “collapsible-container” |
“layout-container” | “table”, “image”, “inline-image”, “sticky”, “layout-container” |
“inline-image” | “image”, “inline-image”, “sticky” |
“poll” | “image”, “inline-image”, “sticky” |
“excalidraw” | “image”, “inline-image”, “sticky” |
These rules are enforced in two ways:
- Existing content that contains these prohibited combinations will be rejected immediately when
codox.start()
is invoked. - Any new content created or inserted by a user that violates these rules will be blocked, and the document will retain a valid state. If an
onBlacklistedInsert
callback is provided, it will be invoked to report the error.
The following utility function is included in the package to validate a document state before passing it to Codox:
onBlacklistedInsert
This optional callback is triggered each time a blacklisted content combination is detected and blocked. This allows the application to respond appropriately, for example, by notifying users that their actions are restricted:
Playground Plugin Polyfills
We have identified some behaviors in certain playground rich text plugins that were unforeseen in multiplayer contexts. To address these issues, we provide polyfills for these plugins when included in the Lexical setup:
Playground Plugin | Polyfill Plugin |
---|---|
FillBGColorPlugin | CodoxFillBGColorPlugin |
FontColorPlugin | CodoxFontColorPlugin |
Basic Codox Integration Sandbox
Extended Codox Integration Sandbox
Additional plugins included:
- Comments
- Undo