v0.47.0 is a monthly release with a lot of bug fixes, particularly related to IME and composition, and is headlined by two new experimental packages:
@lexical/mdast(#8794) — a micromark/mdast-based alternative to@lexical/markdown. Parsing, serialization, and markdown shortcuts all go through the same parser used byremark, so CommonMark + GFM compliance comes for free and there is no second grammar to keep in sync. The original syntax of each construct is preserved on the nodes, so re-serializing produces minimally different Markdown.@lexical/markdownremains the supported default for production apps. See the new Markdown with@lexical/mdastguide.@lexical/a11y(#8591) — framework-agnostic accessibility helpers (ARIA live regions, focus management, roving tab index, focus trap) usable from React, Svelte, Vue, Solid, or vanilla DOM, with React wrappers shipping from@lexical/react. The playground adopts them as part of a WCAG AA reference pass, and the keyboard contracts Lexical follows are documented in the new Keyboard Accessibility guide.
Beyond the headliners: React 18 is now the baseline (see Breaking Changes), the playground gains Find and Replace and a Ruby annotation node with a floating editor, tables learn to spread pasted TSV across cells and get row/column header utilities, and there is a long list of IME/composition, selection, and navigation fixes.
Special recognition once again goes to @mayrang who has been plowing through IME, accessibility, and other input related issues as well as the really cool new Find and Replace and Ruby Annotations playground features.
Breaking Changes
@lexical/react / @lexical/devtools-core — React 17 support dropped (#8782)
React 18 is now the minimum supported version; the react / react-dom peerDependencies require >=18, and React 17 compatibility code paths were removed. If you are already on React 18 or 19, no changes are required.
lexical — DOM element preserved when composing on a segmented TextNode (#8784)
Starting IME composition in the middle of a segmented TextNode (e.g. a mention) previously replaced the node — destroying its DOM element and breaking the browser's composition tracking (caret flashing and styling bleed on Chrome). The node now temporarily switches to normal mode for the duration of composition, keeping the same node key and DOM element, and is cleaned up when composition ends. Subclass transforms or method overrides that assume a segmented node is always in segmented mode must account for this transient state — see the updated TextNode.setMode() documentation.
New APIs
lexical—$getDocument()returns the owner document of the active editor (correct inside a Shadow DOM or iframe), falling back to the global document when there is no active editor; a new@lexical/eslint-pluginrule enforces its use over thedocumentglobal (#8788, #8813)lexical—registerEventListener/registerEventListeners, type-safeaddEventListenerhelpers that return cleanup functions, now used throughout the codebase — see the updated Working with DOM Events guide (#8767)lexical—SET_TEXT_FORMAT_COMMANDsets (rather than toggles) the selection's text format (see Commands); the same PR fixesformatTexttoggle direction (#8807)@lexical/markdown—$generateNodesFromMarkdownStringparses a markdown string into Lexical nodes without inserting them into the document or modifying the selection (#8789)@lexical/table—$setTableRowIsHeaderand$setTableColumnIsHeaderutilities (#8815);$insertTableRowAtNodeand$insertTableColumnAtNodeare now exported (#8791)
Notable Fixes
IME, composition & mobile
- Prevent text duplication on iOS Safari when formatting during composition (#8755)
- Skip ZWSP insertion for format mismatch on Android Chrome (#8769); deduplicate speech-to-text insertion on Android Chrome (#8759)
- Event module globals moved into per-editor
InputState(#8809); refactored IME composition test infrastructure with browser-level coverage (#8793)
Selection & navigation
- ArrowUp/Down no longer skip block decorators (#8775);
deleteLineno longer removes adjacent block decorators (#8744) - Keep selection inside single-child inline elements (#8772); fix navigation across unmergeable TextNode boundaries in inline-grid containers (#8797)
$setBlocksTypeproperly handles block-end focus in backward selections (#8753);insertNodesre-resolves a detached firstBlock (#8764)- Place the block cursor between decorators and shadow roots (#8758); clean up the trailing shadow root after select-all delete (#8751)
deleteCharacterno longer overwrites the X11 PRIMARY selection viaSelection.modify(#8774)- Defer
onUpdatecallbacks during nested commits (#8672)
Markdown, code & tables
- Fence-like lines inside a code block stay content (#8734); prevent formatting on
TabNodeinside code blocks (#8752) - Pasted TSV text spreads across table cells (#8780)
Playground & website
- Find and Replace (#8779) and Ruby annotation node with floating editor (#8741)
- Support Unicode URLs in the autolink matcher (#8787); restore RTL checkbox position in checklists (#8783); forced-colors (high contrast) icon fixes (#8781, #8773)
- Rewritten testing guide on the website (#8811)
What's Changed
- [lexical][lexical-rich-text][lexical-selection] Bug Fix: Fix navigation across unmergeable TextNode boundaries in inline-grid containers (#8797) by @mayrang
- [lexical][lexical-rich-text] Bug Fix: Fix formatText toggle direction and add SET_TEXT_FORMAT_COMMAND (#8807) by @mayrang
- [scripts] Bug Fix: Let npm prompt for OTP when publishing bootstrap stubs (#8820) by @etrepum
- [lexical-playground] Bug Fix: Clear inline font-size when converting to heading (#8800) by @mayrang
- [lexical-table][lexical-playground] Feature: $setTableRowIsHeader and $setTableColumnIsHeader utilities (#8815) by @mayrang
- [lexical-website] Documentation Update: Rewrite testing guide (#8811) by @mayrang
- [lexical-mdast][lexical-rich-text] Feature: @lexical/mdast, a micromark/mdast-based alternative to @lexical/markdown (#8794) by @etrepum
- Make dependency-check resilient to transient registry errors (#8818) by @zurfyx
- [lexical] Refactor: Move event module globals into per-editor InputState (#8809) by @mayrang
- [lexical] Bug Fix: $getDocument() should fall back to the global document when there is no active editor (#8813) by @potatowagon
- [lexical-playground] Bug Fix: Keep cell background color modal open on first click (#8806) by @sahiee-dev
- [lexical-playground] Bug Fix: Use consistent default maxWidth for markdown-imported images (#8810) by @mayrang
- [*][lexical-devtools][lexical-playground] Chore: Update flow, hermes, and babel packages to latest (#8795) by @etrepum
- Add a 7-day pnpm minimumReleaseAge to match the Dependabot cooldown (#8808) by @zurfyx
- [lexical] Chore: Fix tmp package dependency vulnerability (#8802) by @vijayojha89
- [lexical] Chore: Add missing Flow type declarations (#8799) by @mayrang
- [lexical-markdown] Feature: Add $generateNodesFromMarkdownString (#8789) by @mayrang
- [lexical][lexical-playground] Chore: Refactor IME composition test infrastructure and add browser-level coverage (#8793) by @mayrang
- [lexical-playground] Bug Fix: Use viewBox dimensions for unsized Excalidraw output (#8798) by @mayrang
- [lexical-table] Bug Fix: Export $insertTableRowAtNode and $insertTableColumnAtNode (#8791) by @hamo-o
- [lexical-playground][lexical-website] Feature: Add Vercel Analytics and Speed Insights (#8796) by @zurfyx
- [lexical][lexical-eslint-plugin] Feature: Add $getDocument() API and Shadow DOM lint enforcement (#8788) by @mayrang
- [scripts] Bug Fix: strip misplaced pure annotations from prod builds (#8786) by @etrepum
- [lexical] Bug Fix: deleteCharacter overwrites X11 PRIMARY selection via Selection.modify (#8774) by @etrepum
- [lexical-playground] Bug Fix: Support Unicode URLs in autolink matcher (#8787) by @mayrang
- [lexical-table] Feature: Spread pasted TSV text across table cells (#8780) by @mayrang
- [Breaking Change][lexical] Bug Fix: Preserve DOM element when composing on segmented TextNode middle (#8784) by @mayrang
- [Breaking Change][lexical-react][lexical-devtools-core] Chore: Drop React 17 support, baseline is now React 18 (#8782) by @etrepum
- [lexical-playground][lexical] Feature: Ruby annotation node with floating editor (#8741) by @mayrang
- [lexical-playground] Feature: Find and Replace (#8779) by @mayrang
- [lexical-playground] Bug Fix: restore RTL checkbox position in checklist (#8783) by @ryanda9910
- [lexical-rich-text] Bug Fix: Stop ArrowUp/Down from skipping block decorators (#8775) by @mayrang
- [lexical-playground] Bug Fix: Convert remaining icon glyphs to mask-image for forced-colors support (#8781) by @mayrang
- fix(lexical): use
extendsfor type parameter bound in registerEventListeners flow type (#8778) by @potatowagon - [lexical] Bug Fix: Keep selection inside single-child inline elements (#8772) by @mayrang
- [lexical][*] Feature: registerEventListener / registerEventListeners DOM helpers (#8767) by @etrepum
- [lexical-playground] Bug Fix: Restore floating toolbar comment icon after mask-image conversion (#8773) by @mayrang
- [lexical] Bug Fix: Skip ZWSP insertion for format mismatch on Android Chrome (#8769) by @mayrang
- [lexical-a11y][lexical-react][lexical-playground][lexical-website] Feature: @lexical/a11y framework-agnostic accessibility helpers + WCAG AA reference adoption (#8591) by @mayrang
- Add missing copyright headers to 4 source files (#8768) by @xiezhenjia-meta
- [lexical-website] Bug Fix: Remove horizontal scroll on homepage hero (#8760) by @kainulla
- [lexical-selection] Bug Fix: re-resolve detached firstBlock in insertNodes (#8764) by @ochevallier
- [lexical] Modernize InlineFormattableNode Flow stub syntax rejected by fb-www flow strict (#8763) by @potatowagon
- [lexical-utils] Bug Fix: positionNodeOnRange leaking orphan rect nodes when rects shrink (#8762) by @durvesh1992
- docs: fix duplicated words in comments and docs (#8761) by @durvesh1992
- [lexical-selection] Bug Fix: Properly handle block end focus in backward selections during $setBlocksType (#8753) by @ochevallier
- [lexical][lexical-extension] Bug Fix: Align DecoratorTextNode format with TextNode in mixed selections (#8737) by @sahiee-dev
- [lexical] Bug Fix: Clean up trailing shadow root after select-all delete (#8751) by @mayrang
- [lexical][lexical-rich-text] Bug Fix: Place block cursor between decorators and shadow roots (#8758) by @mayrang
- [lexical-playground] Bug Fix: Deduplicate speech-to-text insertion on Android Chrome (#8759) by @mayrang
- [lexical] Bug Fix: Prevent deleteLine from removing adjacent block decorators (#8744) by @mayrang
- build(deps): bump actions/checkout from 6 to 7 in the github-actions group (#8757) by @dependabot
- [ci] Add internal-registry dependency availability check (#8756) by @zurfyx
- [lexical] Bug Fix: Prevent text duplication on iOS Safari when formatting during composition (#8755) by @mayrang
- [lexical-code][lexical-playground] Bug Fix: Prevent formatting on TabNode inside code blocks (#8752) by @mayrang
- [lexical] Bug Fix: Defer onUpdate callbacks during nested commits (#8672) by @Rohithmatham12
- [lexical-extension][lexical-playground] Chore: Some cleanups (#8732) by @levensta
- [lexical-markdown] Bug Fix: keep fence-like lines inside a code block as content (#8734) by @GermanJablo
- v0.46.0 (#8748) by @etrepum
New Contributors
- @Rohithmatham12 made their first contribution in #8672
- @kainulla made their first contribution in #8760
- @durvesh1992 made their first contribution in #8761
- @ochevallier made their first contribution in #8753
- @ryanda9910 made their first contribution in #8783
- @hamo-o made their first contribution in #8791
- @vijayojha89 made their first contribution in #8802
Full Changelog: https://lexical.dev is the project site; compare view: v0.46.0...v0.47.0