How the Lexical Rich Text Editor Is Integrated Into DrawDB for Table Descriptions
DrawDB integrates the Lexical rich text editor into the Table Info side-panel by wrapping it in a dedicated React component that replaces the standard text area when users expand the Description section, allowing formatted text, markdown shortcuts, and links to be persisted to the table's comment property.
DrawDB is an open-source database diagramming tool that stores table metadata—including descriptions—in a comment property. When users need to add rich formatting to table descriptions, the application switches from a plain TextArea to a Lexical-based editor. According to the drawdb-io/drawdb source code, this integration keeps the underlying data model simple while providing a full-featured editing experience.
Architecture of the Lexical Integration
The integration consists of three specialized components working together to render the editor, handle formatting commands, and persist data back to the diagram state.
The RichEditor Component Wrapper
Located at src/components/LexicalEditor/RichEditor.jsx, this component serves as the primary interface between DrawDB and Lexical. It assembles the necessary plugins and configures the editor instance.
The RichEditor function accepts theme, placeholder, initialValue, and onBlur props. It returns a LexicalComposer configured with an initialConfig derived from the table's existing comment. The component mounts several essential plugins:
// src/components/LexicalEditor/RichEditor.jsx
export default function RichEditor({ theme, placeholder, initialValue, onBlur }) {
return (
<LexicalComposer initialConfig={editorConfig(initialValue)}>
<ToolbarPlugin theme={theme} />
<RichTextPlugin
contentEditable={<ContentEditable className="editor-input" />}
placeholder={<Placeholder text={placeholder} />}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin />
<AutoFocusPlugin />
<LinkPlugin />
<ListPlugin />
<AutoLinkPlugin />
<ListMaxIndentLevelPlugin maxDepth={7} />
<MarkdownShortcutPlugin transformers={TRANSFORMERS} />
<ClearEditorPlugin />
</LexicalComposer>
);
}
This architecture allows DrawDB to support markdown shortcuts, auto-linking, list handling, and code highlighting without modifying the core data structure.
ToolbarPlugin for Formatting Controls
The formatting toolbar is provided by src/components/LexicalEditor/ToolbarPlugin.jsx. This component uses the useLexicalComposerContext hook to access the editor instance and dispatch formatting commands.
The plugin renders buttons for bold, italic, links, headings, and lists. When users click a formatting button, the plugin dispatches specific Lexical commands:
// src/components/LexicalEditor/ToolbarPlugin.jsx
function ToolbarPlugin({ theme }) {
const [editor] = useLexicalComposerContext();
const formatText = (format) => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
};
return (
<div className={`toolbar ${theme}`}>
<Button icon="bold" onClick={() => formatText("bold")} />
<Button icon="italic" onClick={() => formatText("italic")} />
<Button icon="link" onClick={() =>
editor.dispatchCommand(INSERT_LINK_COMMAND)}
/>
{/* Additional formatting controls */}
</div>
);
}
TableInfo Component Integration
The TableInfo component at src/components/EditorSidePanel/TablesTab/TableInfo.jsx hosts the description panel. It conditionally renders the RichEditor when the user expands the Description section.
The component manages local state through showComment and commentActiveKey to control visibility. When the panel opens, it passes the current table comment as initialValue and handles persistence via the onBlur callback:
// src/components/EditorSidePanel/TablesTab/TableInfo.jsx
{showComment && (
<Collapse activeKey={commentActiveKey} onChange={setCommentActiveKey}>
<Panel header={t("description")} itemKey="1">
<RichEditor
theme={layout.theme}
placeholder={t("table_description")}
initialValue={data.comment}
onBlur={(newComment) =>
updateTable(data.id, { comment: newComment })
}
/>
</Panel>
</Collapse>
)}
Data Flow and Persistence
The Lexical rich text editor integration follows a strict unidirectional data flow that preserves DrawDB's undo/redo capabilities and save state management.
Loading and Initialization
- Initial Data:
TableInforeceives a table object (data) containing thecommentproperty from the diagram context. - Panel Activation: Clicking the Description header triggers
setCommentActiveKey("1")andsetShowComment(true). - Editor Mount:
RichEditorinitializes witheditorConfig(initialValue), converting the plain text comment into Lexical's internal state tree.
Editing and Saving
- User Input: As users type, Lexical's internal state updates through the mounted plugins. The
HistoryPlugintracks changes for undo/redo functionality. - Persistence: On blur events, the editor state is serialized back to plain text using
editor.getEditorState().read(() => $getRoot().getTextContent()). - State Update: The
onBlurcallback invokesupdateTable(data.id, { comment: newValue }), which triggers:- Updates to the undo stack via
setUndoStack - Updates to the redo stack via
setRedoStack - A save state change to
State.SAVINGviasetSaveState
- Updates to the undo stack via
This flow ensures that the Lexical rich text editor can handle complex formatting internally while the DrawDB application continues to treat table descriptions as simple strings in the data model.
Why DrawDB Chose Lexical
DrawDB selected Lexical for its plugin-based architecture and minimal core footprint. Unlike monolithic editors, Lexical allows DrawDB to import only necessary features—markdown shortcuts, list handling, and code highlighting—keeping the bundle size small. The separation between the editor's internal state and the application's data model means the comment property remains a string, avoiding complex migration requirements while still supporting rich text capabilities.
Key Implementation Files
src/components/LexicalEditor/RichEditor.jsx: Wraps Lexical plugins and exposes the editor UI.src/components/LexicalEditor/ToolbarPlugin.jsx: Provides the formatting toolbar used by the editor.src/components/EditorSidePanel/TablesTab/TableInfo.jsx: Hosts the description panel and integratesRichEditorfor the table's comment field.src/context/DiagramContext.jsx: SuppliesupdateTableand diagram-state helpers that persist comment changes.
Summary
- DrawDB stores table descriptions in the
commentproperty of table objects, treating them as plain strings in the data model. - The Lexical rich text editor is wrapped in a
RichEditorcomponent atsrc/components/LexicalEditor/RichEditor.jsxthat assembles necessary plugins includingToolbarPlugin,HistoryPlugin, andMarkdownShortcutPlugin. TableInfoconditionally renders the editor when users expand the Description section, passing the current comment as initial state.- Changes are persisted on blur events via the
updateTablehook, which updates the diagram's undo/redo stack and triggers save states. - This architecture allows rich formatting (bold, italics, links, lists) without changing the underlying database schema or data structures.
Frequently Asked Questions
How does DrawDB convert Lexical editor state back to plain text for storage?
DrawDB reads the editor's content using Lexical's $getRoot().getTextContent() method inside an editor state read operation. When the onBlur event fires in the RichEditor component, it serializes the rich text tree to a plain string and passes it to the updateTable function, ensuring the comment property always contains simple text compatible with the existing data model.
Can users use markdown shortcuts in the DrawDB table description editor?
Yes. The RichEditor component includes MarkdownShortcutPlugin with TRANSFORMERS enabled, allowing users to type markdown syntax (such as # for headings or - for lists) to trigger automatic formatting conversion without leaving the keyboard.
What happens to formatting when exporting or importing diagrams in DrawDB?
Since DrawDB persists only the plain text representation of the description via $getRoot().getTextContent(), formatting metadata is not stored in the diagram JSON structure. When a diagram is reopened, the RichEditor initializes with this plain text, and users must reapply any formatting. This design choice maintains backward compatibility and keeps the file format simple.
Where is the toolbar configuration defined for the Lexical editor in DrawDB?
The toolbar is implemented in src/components/LexicalEditor/ToolbarPlugin.jsx. This component uses the useLexicalComposerContext hook to access the editor instance and dispatches commands like FORMAT_TEXT_COMMAND and INSERT_LINK_COMMAND when users click formatting buttons. The toolbar receives the current theme via props to maintain visual consistency with the rest of the application.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →