Rich and Markdown Text Editor
Description
Introduces Lexical as a Markdown/Rich Text editor and renderer This PR is ready for review as-is. While structure and cleanup are an on-going work, the editor has been QA'd extensively and logic has been refined across these two months.
Screenshots
Comment editor view:
Toplevel editor view:
Toolbar
Toolbar with shortcuts
Toolbar with dropdowns
Floating Toolbar
Media
Media captions, resize and DnD
https://github.com/user-attachments/assets/6020d937-c756-4f19-bf2e-f3ce136db047
Decorators
Table of contentshttps://github.com/user-attachments/assets/4505889b-18b7-405e-b628-a7e03e9e078f
Features
core
- [x] rich text
- [x] markdown mode
- [x] formik integration
- [x] local-storage draft saving
- [x] max-length support
- [x] auto-focus support
- [x] keyboard shortcuts
- [x] undo/redo history
- [x] shared history for nested editors
formatting
- [x] bold, italic, underline, strikethrough
- [x] subscript, superscript
- [x] inline code
- [x] code blocks
- [x] block quotes
- [x] headings (H1-H6)
- [x] paragraphs
- [x] text alignment (left, center, right, justify)
- [x] indentation
lists
- [x] bullet, numbered, check lists
- [x] parentheses ordered lists (e.g.
1))
content
- [x] math equations (KaTeX) - inline and block
- [x] tables with action menu
- [x] spoilers (inline and container)
- [x] table of contents generator
media
- [x] image and video uploads with fees
- [x] drag and drop upload
- [x] image captions (nested editor)
- [x] image resizing
- [x] YouTube, Twitter, Spotify, PeerTube, Nostr, Wavlake embeds
- [x] final media type by checking on insert or db upsert
links
- [x] autolink detection
- [x] link editor popup
- [x] SN item mentions (#123456)
- [x] link fallback for failed media
mentions
- [x] user mentions (@username) with popover
- [x] territory mentions (~territory) with popover
- [x] item mentions
- [x] typeahead lazy-loaded suggestions
markdown
- [x] full markdown ↔ Lexical transformation
- [x] markdown shortcuts in rich mode
- [x] high-fidelity round-trip conversion
- [x] highlighted markdown via Shiki
server
- [x] headless editor for server operations
- [x] HTML generation from Lexical state
- [x] HTML sanitization (DOMPurify)
- [x] media checks
- [x] legacy content migration worker
UX
- [x] floating toolbar for selections
- [x] fixed toolbar for formatting
- [x] mode switcher (markdown/rich)
- [x] upload progress indicators
- [x] copy to clipboard for math nodes
- [x] link editing popup
- [x] character count display
New things
- KaTeX is used in place of MathJax to render equations and LaTeX.
-
Shiki is used in place of React Syntax Highlighter to highlight code blocks - it is undoubtedly faster and lighter than RSH, reaching
4kBof size in the bundle (this has to be re-verified later) - Uploads are now concurrently processed, also featuring a percentage, with placeholder per each upload - the user can continue to write while it uploads
-
MediaOrLinkpreserves scroll on load, supports captions and resize - Embeds refactor with a load timeout that spawns an error component (context)
- HTML from a lexical JSON state is parsed server-side via Linkedom, a performance-focused DOM simulator
- TBD, a lot has changed from the last update
Additional Context
TBD, a lot has changed from the last update
Progress
TBD, a lot has changed from the last update
Checklist
Are your changes backward compatible? Please answer below:
For example, a change is not backward compatible if you removed a GraphQL field or dropped a database column. Yes! Everything has backwards compatibility. But it also does not depend on existing features that are going to be replaced.
On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below: tbd
For frontend changes: Tested on mobile, light and dark mode? Please answer below: UI is tested on both mobile and desktop.
Did you introduce any new environment variables? If so, call them out explicitly here: n/a
Did you use AI for this? If so, how much did it assist you? It's a big PR with Lexical being a novel paradigm.
Ask: better lexical understanding, things that weren't clear in documentation or in code, best practices Agent: massive restructuring, autocomplete, lexical overrides with lint
[!NOTE] Introduce a Lexical-based rich/markdown editor and renderer, add schema/API fields for
lexicalState/html, server HTML generation, and a worker-driven migration for legacy content, with broad UI integration and media/mention tooling.
- Backend:
- DB: add
Item.lexicalState(JSONB) andItem.html; createLexicalMigrationLog/LexicalBatchMigrationLog.- GraphQL: add
lexicalState/htmltoItem; acceptlexicalStatein item/sub/user mutations; newexecuteConversionmutation.- Resolvers: prepare Lexical state, generate sanitized HTML, upload ID extraction from text, SN item link regex.
- Workers: add partitioned legacy content migration jobs; server utils for headless Lexical and HTML generation (DOMPurify/LinkeDOM).
- Editor/Renderer:
- New Lexical editor/reader, contexts, theme, toolbar (floating/fixed), shortcuts, history, drafts, max-length.
- Plugins: uploads with progress/DnD, link editor, mentions (@, ~, #), math (KaTeX), tables with action menu, spoilers, ToC, code highlighting (Shiki), media embeds.
- UI Integration:
- Replace
MarkdownInputwithLexicalInputacross forms (posts, comments, jobs, polls, bounties, bio, sub descriptions).- Render comments/items via Lexical when available; dev actions for conversion; truncation and outlawed content handling.
- Media upload refactor (S3 XHR with progress, filtering, EXIF strip),
MediaOrLinkscroll-preserving and resizing/captions.- Misc: tooltip, copy button tweaks, layout/CSS for editor; route
/u/:idredirect.Written by Cursor Bugbot for commit bc69de5d376d88451fd7beda4a5d8eb1f47605f4. This will update automatically on new commits. Configure here.
All alerts resolved. Learn more about Socket for GitHub.
This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
| Diff | Package | Supply Chain Security |
Vulnerability | Quality | Maintenance | License |
|---|---|---|---|---|---|---|
| @lexical/clipboard@0.38.2 | ||||||
| @lexical/rich-text@0.38.2 | ||||||
| @lexical/selection@0.38.2 | ||||||
| @lexical/utils@0.38.2 | ||||||
| @lexical/code-shiki@0.38.2 | ||||||
| @lexical/history@0.38.2 | ||||||
| @lexical/html@0.38.2 | ||||||
| linkedom@0.18.12 | ||||||
| @lexical/headless@0.38.2 | ||||||
| dompurify@3.2.6 | ||||||
| react-syntax-highlighter@15.5.0 ⏵ 15.6.6 | ||||||
| katex@0.16.11 ⏵ 0.16.22 | ||||||
| @lexical/react@0.38.2 | ||||||
| lexical@0.38.2 |
Woot! The bug hunt begins! I found a couple just now.
Transforms appear to be unreliable:
https://github.com/user-attachments/assets/96162440-7000-469e-9d82-f22bcc377e8b
Sometimes the editor will get into a state where the cursor isn't in a paragraph block and new blocks will be weird (eg code block). I seemed to trigger this behavior after transforming back and forth to markdown mode:
https://github.com/user-attachments/assets/2a21df4a-3280-4c2e-aafc-181c46e1b27c
Transforms appear to be unreliable
wow you spotted a very recent bug haha lexical/7974 I'll get to it 🫡
note: transformations need serious QA because covering a lot of scenarios can be really messy.
the cursor isn't in a paragraph block
Ah, might've reduced selection placement calls too much...