v0.52.0
v0.52.0 is an ad-hoc release targeting a few fixes to mobile text input, but carries a number of other updates accumulated in the past week as we move towards Lexical 1.0. We did a pass to modernize the documentation focusing on the latest features. @lexical/mdast now uses one configurable MdastExtension for import and export, headless editors can be built entirely from extensions, and selection notifications have a consistent timing contract. There are also fixes for deletion, horizontal caret scrolling, drag-and-drop and mobile input.
lexical—SELECTION_CHANGE_COMMANDconsistently runs before DOM reconciliation, inside the pending writable update. This includes automaticNodeSelectionandTableSelectionnotifications that previously ran after reconciliation.$getSelection()returns the pending selection;$getPreviousSelection()returns the last committed selection. Eligible programmatic changes now notify without waiting for a nativeselectionchangeevent. Listener edits join the same commit, and handlers that change the selection must converge. A listener that throws can now abort the whole pending update, including the edit that triggered the notification, and listeners inherit that update's tags, so content edits made during aCOLLABORATION_TAGorHISTORIC_TAGupdate are not synced to Yjs peers. Move DOM-dependent work such as element lookup, focus checks and floating UI positioning into$onUpdate(() => editor.read('latest', () => { /* ... */ })), reading selection and nodes inside that callback. UseregisterUpdateListenerfor UI that must respond to every commit, including content-only changes (#9219, selection timing guide)lexical/@lexical/html— Default HTML export now honorsDOMRenderExtension$createDOMoverrides. This affects nodes that inheritLexicalNode.exportDOMor callsuper.exportDOM(editor), including text and paragraphs. If an override was intended only for the live editor, review the HTML it now exports. CustomexportDOMimplementations that create their own elements can still bypass this hook;$updateDOMand$decorateDOMremain reconciliation-only, and$exportDOMhandles export-specific changes (#9231)lexical—LexicalNode.getCommonAncestoris removed. Use$getCommonAncestor(a, b)?.commonAncestor ?? null. This is not quite a direct substitution: the removed method first replaced non-element arguments with their parents, while the function compares the supplied nodes and can return a text node when both arguments are that node. Pass the parents of non-element nodes if you need the old behavior, and use type guards instead of the old unchecked generic type argument (#9238)
@lexical/mdast—MdastImportExtensionandMdastExportExtensionare deprecated aliases ofMdastExtension. Move configuration toMdastExtensionand replaceMdastImportExtensionOutput/MdastExportExtensionOutputwithMdastExtensionOutput. The package is experimental, and these aliases are intended to remain for only one release (#9198)
@lexical/mdast— Unified Markdown configuration and inherited export rules.MdastExtensionowns both import and export, and feature extensions include it automatically. Export rules accept a node class or type string and apply to subclasses, with more specific rules taking precedence. ATextNoderule can therefore handle tabs and custom text subclasses without separate registrations (#9198)@lexical/mdast— Import/export middleware throughcontext.next(). Delegate conversion of the same node to the remaining handlers, then return or modify their output. Export chains try remaining same-type rules before ancestor rules. Usecontext.next()to delegate:nullretains its existing meaning of default export or omitted import, while[]omits content in either direction. Formatted text from middleware participates in text merging; custom structure or metadata is preserved as-is (#9198)@lexical/headless—HeadlessExtensionworks withbuildEditorFromExtensionsfor server-side processing and tests. It marks the editor as headless and prevents attaching a DOM root. UnlikecreateHeadlessEditor, it keeps listener registration methods available, so extensions that register root listeners can still be used (#9249)
Selection & editing
- Backspace over all text in the first block preserves the empty block and its type (#9236); select-all deletion restores an editable paragraph when the root still contains slots such as footnotes (#9240); line deletion correctly resolves endpoints inside text-bearing inline decorators (#9247)
- Dropping dragged text on the edge of its own selection no longer deletes it (#9241); persistent selection highlights retain coverage across mixed font sizes and partially overlapping rectangles (#9196)
- Lexical-controlled caret moves reveal the caret horizontally in code blocks and other scrolling containers, including table wrappers. Horizontal scrolling respects
scroll-padding, with updated playground styling to keep the caret clear of the code gutter (#9215) - Focus commands triggered during DOM selection synchronization no longer produce spurious read-only warnings; dispatching commands from an explicit read context still warns (#9230)
Mobile input & recovery
- iOS tracks explicit Shift key events so Shift+Enter can insert a line break without treating automatic capitalization as Shift. Ordinary Enter continues to insert paragraphs; when capitalization has already highlighted Shift, it must be toggled off and on to request a line break (#9242)
- The input-suppression workaround after handled Backspace or select-all is limited to macOS Chromium, preventing legitimate text input from being discarded on other platforms (#9251)
setEditorStatewith a childless root warns and recovers to an empty paragraph in production. Development builds still report the invalid state throughonError(#9183)
Performance & signals
- Writable nodes are cached during pending updates, reducing repeated node-map lookups (#9169)
@lexical/extensionraises its@preact/signals-coredependency to^1.14.4, fixing stale computed values after a batch changes a signal and restores its original value (#9248)
Playground & docs
- Getting-started guides now use module-level root extensions, with five live editors, examples drawn directly from runnable source, and Open in StackBlitz buttons. Custom-feature examples demonstrate
$configschemas, NodeState, and HTML import/export through extensions (#9237) - The introduction, Concepts and Serialization guides have been rewritten around current APIs, with Mermaid diagrams, an interactive update lifecycle explanation and a dedicated comparison with ProseMirror. Older setup and serialization APIs remain documented in Legacy sections (#9249)
- Numerous API names, snippets and lifecycle descriptions have been corrected throughout the docs, most of them by @potatowagon. API reference links now point to the right GitHub source paths and resolve external types (#9204, #9220)
- Playground Find & Replace calculates offsets correctly across decorators and slots (#9186)
- v0.51.0 by @etrepum in https://github.com/facebook/lexical/pull/9178
- [lexical] Refactor: Cache writable nodes during pending updates by @etrepum in https://github.com/facebook/lexical/pull/9169
- [lexical-website] Documentation Update: fix $insertList argument in the commands guide by @potatowagon in https://github.com/facebook/lexical/pull/9188
- [lexical-website] Documentation Update: seed the editor state with setEditorState, not registerRichText by @potatowagon in https://github.com/facebook/lexical/pull/9189
- [lexical-website] Documentation Update: title the history page after its public API, not useHistory by @potatowagon in https://github.com/facebook/lexical/pull/9190
- [lexical-website] Documentation Update: use the real plugin component names in the editor-state React example by @potatowagon in https://github.com/facebook/lexical/pull/9191
- [lexical-website] Documentation Update: getElementByKey returns a DOM element, not a node by @potatowagon in https://github.com/facebook/lexical/pull/9192
- [lexical] Bug Fix: recover from an empty editor state instead of throwing by @potatowagon in https://github.com/facebook/lexical/pull/9183
- [lexical-playground] Bug Fix: Fix Find & Replace offsets across decorators and slots by @Monier-Ayman in https://github.com/facebook/lexical/pull/9186
- [lexical-website] Documentation Update: the deserialization hook is importJSON, not importFromJSON by @potatowagon in https://github.com/facebook/lexical/pull/9199
- [lexical-website] Documentation Update: useReactDecorators, and the three missing TextNode formats by @potatowagon in https://github.com/facebook/lexical/pull/9201
- [lexical-website] Documentation Update: clone is synthesized for $config nodes, and fix a setSomeData typo by @potatowagon in https://github.com/facebook/lexical/pull/9202
- [lexical-website] Documentation Update: node-replacement config uses nodes:, not nodes= by @potatowagon in https://github.com/facebook/lexical/pull/9203
- [lexical-website] Bug Fix: Include packages/ in API docs GitHub source links by @etrepum in https://github.com/facebook/lexical/pull/9204
- [lexical-website] Documentation Update: fix syntax errors, outdated APIs, and broken links in Node Transforms guide by @jaideepkrishna2008-ui in https://github.com/facebook/lexical/pull/9197
- [lexical-code-core][lexical-code-prism][lexical-code-shiki] Refactor: move the duplicated updateCodeGutter into @lexical/code-core by @Om-singhaI in https://github.com/facebook/lexical/pull/9164
- [lexical-mdast] Feature: Unify MdastExtension and inherit export rules by @etrepum in https://github.com/facebook/lexical/pull/9198
- [lexical-website] Documentation Update: fix two nodes.mdx snippets that do not compile by @potatowagon in https://github.com/facebook/lexical/pull/9200
- [lexical-website] Documentation Update: show $initialEditorState, not a function passed to createEditor by @potatowagon in https://github.com/facebook/lexical/pull/9205
- [lexical-website] Documentation Update: correct the shadow-DOM support table and two API references by @potatowagon in https://github.com/facebook/lexical/pull/9206
- [lexical-website] Documentation Update: fix the test path in the traversals maintenance comment by @potatowagon in https://github.com/facebook/lexical/pull/9207
- [lexical-website] Documentation Update: correct four claims in the extension lifecycle guide by @potatowagon in https://github.com/facebook/lexical/pull/9208
- [lexical-website] Documentation Update: re-sync the TabIndentationExtension snippet with its source by @potatowagon in https://github.com/facebook/lexical/pull/9209
- [lexical-website] Documentation Update: fix the broken snippets in the extensions migration guide by @potatowagon in https://github.com/facebook/lexical/pull/9211
- [lexical-website] Documentation Update: call the system Lexical Extensions, not Lexical Builder by @potatowagon in https://github.com/facebook/lexical/pull/9212
- [lexical-website] Documentation Update: fix two extension names that do not exist by @potatowagon in https://github.com/facebook/lexical/pull/9210
- [lexical-website] Documentation Update: add HMRExtension and KeyboardShortcutsExtension to the included list by @potatowagon in https://github.com/facebook/lexical/pull/9213
- [lexical-website] Documentation Update: fix seven incorrect API references in the DOM import guide by @potatowagon in https://github.com/facebook/lexical/pull/9222
- [lexical-website] Documentation Update: correct DOMExportOutput, DOMConversion priority, and the HeadingNode examples by @potatowagon in https://github.com/facebook/lexical/pull/9223
- [lexical-website] Documentation Update: fix the collaboration snippets and two stale playground references by @potatowagon in https://github.com/facebook/lexical/pull/9225
- [lexical-website] Documentation Update: correct five stale facts in the maintainers guide by @potatowagon in https://github.com/facebook/lexical/pull/9226
- [lexical-website] Documentation Update: setEditorState warns and recovers in production, it does not always throw by @potatowagon in https://github.com/facebook/lexical/pull/9228
- [lexical-website] Documentation Update: point the selection guide at NodeCaret by @potatowagon in https://github.com/facebook/lexical/pull/9229
- [lexical-website] Bug Fix: resolve external API links and shorten submodule labels by @etrepum in https://github.com/facebook/lexical/pull/9220
- [lexical] Bug Fix: Avoid read-only warnings for commit-time focus commands by @etrepum in https://github.com/facebook/lexical/pull/9230
- [lexical][lexical-html] Breaking Change: honor $createDOM overrides in default DOM export by @etrepum in https://github.com/facebook/lexical/pull/9231
- [lexical-website] Documentation Update: document the full update-listener payload and the cascade guard by @potatowagon in https://github.com/facebook/lexical/pull/9227
- [lexical-compiler] Bug Fix: Normalize temporary paths in watcher tests by @minwookshin in https://github.com/facebook/lexical/pull/9195
- [lexical][lexical-table][lexical-playground][lexical-website] Breaking Change: Standardize selection notification timing by @etrepum in https://github.com/facebook/lexical/pull/9219
- [benchmarks] Chore: Migrate benchmarks to vitest 5 and add type checking in CI by @etrepum in https://github.com/facebook/lexical/pull/9235
- [lexical][lexical-code-core][lexical-playground] Bug Fix: reveal the caret in code blocks and other containers that scroll sideways by @Om-singhaI in https://github.com/facebook/lexical/pull/9215
- [lexical] Bug Fix: Preserve first block after backward range deletion by @Abdul-Azhar-Jamesh in https://github.com/facebook/lexical/pull/9236
- [lexical-selection][lexical-utils] Bug Fix: Preserve selection coverage across mixed typography by @minwookshin in https://github.com/facebook/lexical/pull/9196
- [lexical-clipboard] Bug Fix: Keep dragged text when it is dropped on the edge of its own selection by @kwy404 in https://github.com/facebook/lexical/pull/9241
- [lexical] Breaking change: Remove LexicalNode.getCommonAncestor by @mayrang in https://github.com/facebook/lexical/pull/9238
- [lexical] Bug Fix: Handle select-all deletion with root slots by @etrepum in https://github.com/facebook/lexical/pull/9240
- [lexical-website] Documentation Update: Document ErrorBoundary configuration for PlainTextExtension by @dvd233 in https://github.com/facebook/lexical/pull/9182
- [lexical] Bug Fix: resolve line deletion endpoints inside inline decorators by @maximilliangrand in https://github.com/facebook/lexical/pull/9247
- [lexical] Bug Fix: Limit handled selection input suppression to macOS Chrome by @etrepum in https://github.com/facebook/lexical/pull/9251
- [lexical-playground] Chore: Harden nested editor selection ownership test by @etrepum in https://github.com/facebook/lexical/pull/9243
- [lexical-extension] Chore: Update signals-core to 1.14.4 by @etrepum in https://github.com/facebook/lexical/pull/9248
- [lexical-website][examples] Documentation: Modernize the getting-started section by @etrepum in https://github.com/facebook/lexical/pull/9237
- [lexical] Bug Fix: Track explicit Shift state for iOS line breaks by @etrepum in https://github.com/facebook/lexical/pull/9242
- [lexical][lexical-headless][lexical-website] Documentation Update: Rewrite the introduction and modernize the Concepts, Serialization docs and examples by @etrepum in https://github.com/facebook/lexical/pull/9249
- @Monier-Ayman made their first contribution in https://github.com/facebook/lexical/pull/9186
- @jaideepkrishna2008-ui made their first contribution in https://github.com/facebook/lexical/pull/9197
- @minwookshin made their first contribution in https://github.com/facebook/lexical/pull/9195
- @Abdul-Azhar-Jamesh made their first contribution in https://github.com/facebook/lexical/pull/9236
- @kwy404 made their first contribution in https://github.com/facebook/lexical/pull/9241
- @dvd233 made their first contribution in https://github.com/facebook/lexical/pull/9182
- @maximilliangrand made their first contribution in https://github.com/facebook/lexical/pull/9247
Full Changelog: https://github.com/facebook/lexical/compare/v0.51.0...v0.52.0
v0.51.0
v0.51.0 is a monthly release with one large new feature: nodes can now declare their JSON serialization as a schema on $config. This declarative schema is faster, safer, and more flexible than the hand-written methods. The metadata it provides enables a compact export option with all default values elided, the code generator that provides faster import and export for every node that lexical ships, a new @lexical/fast-check package for property-based tests, and it provides a path to future features that rely on knowing the structure of the nodes (e.g. additional codecs and dev tools).
This is a big step towards Lexical 1.0, the next few releases are expected to be focused on moving everything (including docs and examples) to the latest Extension and $config APIs and removing deprecated functionality. Two related changes in this release are that we are publishing ESM-only to npm now (cjs builds are still supported in the source tree), and LexicalComposer is deprecated for LexicalExtensionComposer. Expect anything @deprecated to be removed soon.
- npm packages are ESM only. Every package declares
"type": "module"and itsexportsmap offersdevelopment/production/defaultconditions with norequirebranch; the CommonJS build remains in-tree only for Meta's www. Bundlers are unaffected. CommonJS code canrequire()the packages on Node.js 20.19+ (the builds have no top-levelawait), and older Node.js must useawait import(...)— but a dependency the app also loads throughrequire()can then exist twice, which breaks handing its objects to Lexical (yjsdocs to@lexical/yjs,@preact/signals-coresignals from@lexical/extension), so load those as ESM too. Metro bundles both builds unless you add the condition for Lexical's packages; see the module formats FAQ (#9127) lexical—exportJSONmay serialize the instance as-is. A property declared withwithFieldis read straight off the node instead of through its accessor, soexportJSONno longer resolvesgetLatest()for you and a stale reference can write stale values (and a property whose accessor a subclass overrode still resolves, so one object can mix the two). Nothing inside Lexical is affected — the walk, the clipboard selection export andeditorState.toJSON()all start from the node map — but callgetLatest()yourself on a reference you kept across a mutation (#8602)@lexical/code— the deprecated Prism re-exports are gone, along with the@lexical/code-prismdependency (so Prism no longer lands in a bundle that only imports@lexical/code). ImportCODE_LANGUAGE_FRIENDLY_NAME_MAP,CODE_LANGUAGE_MAP,getCodeLanguageOptions,getCodeLanguages,getCodeThemeOptions,getLanguageFriendlyName,normalizeCodeLanguage(formerly alsonormalizeCodeLang),PrismTokenizerandregisterCodeHighlightingfrom@lexical/code-prism(#9141)
@lexical/react—LexicalComposeris deprecated in favor ofLexicalExtensionComposerand is expected to be removed in a future major.LexicalComposercannot accept extensions, so any feature shipped as one is unreachable from an editor it builds; the migration is usually a two-line change (#9168, React extensions guide)
lexical— Declarative serialization schemas (experimental). A node that uses$configdeclares its serialized properties once in the newjsonproperty, and that single declaration drivesimportJSON,updateFromJSONandexportJSON:nodeSchema,withField/withAccessors, and the value combinators (stringValue,numberValue,booleanValue,enumValue,arrayValue,objectValue,unionValue,rawValue,transformValue,nullable,optional, …). Every built-in node declares one, and most custom nodes now need no JSON serialization code at all. Output is unchanged by default (#8602, serialization docs).lexical— Compact JSON export, opt-in viaeditorState.toJSON(true)or$withCompactExport(true, cb)(with$isCompactExport()for schema getters, plus$exportNodeJSONand theCompactSerializedEditorState/ParsableSerializedEditorState/LexicalParseJSON/SerializedPartialtypes). It omits properties equal to their schema default, properties the parser derives, and the deprecatedversion. The raw objects are well under half the legacy size — which matters for structured clones and worker messages — but after gzip the two are a wash. Both forms parse back to the same document; only a Lexical new enough to know the schemas can read the compact one, so keep writing the legacy form until every reader is upgraded (#8602)@lexical/compiler— Generated serialization code. Every built-in node class ships straight-line serialization generated from its own schema at build time, producing byte-identical JSON to the schema-driven path that continues to serve custom nodes (#8602)@lexical/fast-check— New package deriving fast-check arbitraries from those schemas:nodeArbitrary(NodeClass)generates exactly the serialized JSON a node's parser accepts, each property independently present or absent. Useful for the bugs fixtures hide, such as a propertyafterCloneFromforgot to copy.fast-checkis a peer dependency;getComposedSchemaFieldsin core inspects a class's schema without generating anything (#8602)@lexical/extension— Published as subpath exports, one entry per extension (@lexical/extension/AutoFocusExtension, …), with compiler and lint enforcement of the source import convention. The barrel import is unchanged, and shared modules such as signals keep a single instance (#9161). This is primarily only useful as a consumer if you are not using tree-shaking.
Bundling, tree-shaking & types
- A production import of only
createCommandno longer retains the editor (#9121), and the remaining module-scope side effects that defeated tree-shaking are gone, with a bare-import residue check now run over every entry (#9124); extension editors build under loose-mode transpilation (#9134) - Flow:
defineExtensionwas uncallable, making the extension types unusable (#9132); declarations can now express an extension with dependencies (#9176); modern variance keywords survive into the www stubs (#9154)
Selection & editing
- No redundant selection-change command on Safari link selection (#9163);
TextNode.setMode,setTextContentandisSimpleTextread the latest state (#9162);$removeTextFromCaretRangeno longer leaves a childless list or table as the root's only child (#9116); a text entity keeps the style and detail of the text it replaces (#9130); selection overlay listeners are notified when rectangles are removed (#9117)
Lists, tables & Markdown
- Indenting between two nested lists no longer converts the second list's type (#9118);
$mergeCellsno longer keeps the empty paragraph of the target cell (#9122); text left outside a Markdown link keeps its format (#9131)
Playground & docs
- Card/Review CSS placeholders are cleared reliably on paste in Safari (#9129) and releasing a CardNode drag no longer selects the node (#9135); new docs on Lexical being a singleton per app, and why a library must declare it as a peer dependency (#9125)
Plus the usual dependency updates across the rollup, shikijs, vitest, docusaurus/typedoc and flow/hermes groups.
- v0.50.0 by @etrepum in https://github.com/facebook/lexical/pull/9110
- [lexical][lexical-compiler] Bug Fix: Let esbuild drop the editor from a createCommand-only production import by @zurfyx in https://github.com/facebook/lexical/pull/9121
- [*] Bug Fix: Remove the remaining module-scope side effects that defeat tree-shaking by @etrepum in https://github.com/facebook/lexical/pull/9124
- [lexical-playground] Bug Fix: clear Card/Review CSS placeholders reliably on paste in Safari by @sahiee-dev in https://github.com/facebook/lexical/pull/9129
- [lexical-website] Documentation Update: document that Lexical is a singleton per app and libraries must declare it as a peer dependency by @potatowagon in https://github.com/facebook/lexical/pull/9125
- [lexical-markdown] Bug Fix: text left outside a markdown link keeps its format by @Om-singhaI in https://github.com/facebook/lexical/pull/9131
- [lexical] Fix: make the extension Flow types usable (defineExtension was uncallable) by @potatowagon in https://github.com/facebook/lexical/pull/9132
- build(deps-dev): bump esbuild from 0.27.7 to 0.28.1 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9123
- [lexical-table] Bug Fix: $mergeCells no longer keeps the empty paragraph of the target cell by @Om-singhaI in https://github.com/facebook/lexical/pull/9122
- [lexical-utils] Bug Fix: notify when selection overlay rectangles are removed by @mehuljariwala in https://github.com/facebook/lexical/pull/9117
- [lexical] Bug Fix: $removeTextFromCaretRange no longer leaves a childless list or table as the root's only child by @Om-singhaI in https://github.com/facebook/lexical/pull/9116
- [lexical-playground] Bug Fix: avoid node selection on CardNode drag release by @kavyansh18 in https://github.com/facebook/lexical/pull/9135
- [lexical-extension] Fix: use Array.from over iterable spread so extension editors build under loose-mode transpilation by @potatowagon in https://github.com/facebook/lexical/pull/9134
- [lexical-text] Bug Fix: a text entity keeps the style and detail of the text it replaces by @Om-singhaI in https://github.com/facebook/lexical/pull/9130
- [*] Breaking change: Publish ESM only to npm and keep the CommonJS build for www by @etrepum in https://github.com/facebook/lexical/pull/9127
- [lexical-code] Breaking change: drop the deprecated prism re-exports and the @lexical/code-prism dependency by @etrepum in https://github.com/facebook/lexical/pull/9141
- build(deps-dev): bump vitest from 4.1.8 to 4.1.11 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9140
- build(deps): bump the docusaurus-and-typedoc group with 13 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9142
- build(deps-dev): bump the flow-and-hermes group with 4 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9143
- build(deps-dev): bump baseline-browser-mapping from 2.10.33 to 2.11.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9139
- build(deps): bump the shikijs group with 6 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9145
- build(deps): bump the rollup group across 1 directory with 5 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9144
- [lexical-list] Bug Fix: indenting between two nested lists no longer converts the second list's type by @Om-singhaI in https://github.com/facebook/lexical/pull/9118
- [*] Bug Fix: Keep modern Flow variance keywords in the www Flow stubs by @potatowagon in https://github.com/facebook/lexical/pull/9154
- build(deps-dev): bump the dev-dependencies group across 1 directory with 26 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9150
- build(deps-dev): bump flow-bin from 0.330.0 to 0.331.0 in the flow-and-hermes group by @dependabot[bot] in https://github.com/facebook/lexical/pull/9156
- [lexical-extension][*] Refactor: publish @lexical/extension as subpath exports with compiler+lint enforcement by @etrepum in https://github.com/facebook/lexical/pull/9161
- [lexical] Bug Fix: Avoid redundant selection change command by @levensta in https://github.com/facebook/lexical/pull/9163
- [lexical] Bug Fix: TextNode setMode, setTextContent and isSimpleText read the latest state by @Dev-next-gen in https://github.com/facebook/lexical/pull/9162
- [lexical-react] Chore: Deprecate LexicalComposer in favor of LexicalExtensionComposer by @potatowagon in https://github.com/facebook/lexical/pull/9168
- build(deps-dev): bump eslint from 10.9.1 to 10.10.0 in the dev-dependencies group across 1 directory by @dependabot[bot] in https://github.com/facebook/lexical/pull/9158
- build(deps): bump date-fns from 4.1.0 to 4.4.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9159
- [lexical][*] Feature: node JSON serialization schemas, with compact export by @etrepum in https://github.com/facebook/lexical/pull/8602
- build(deps): bump @babel/parser from 8.0.0 to 8.0.4 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9160
- build(deps): bump immutable from 4.3.8 to 4.3.9 by @dependabot[bot] in https://github.com/facebook/lexical/pull/9175
- build(deps-dev): bump the vitest group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/9157
- [lexical] Fix: Flow declarations cannot express an extension with dependencies by @potatowagon in https://github.com/facebook/lexical/pull/9176
- @mehuljariwala made their first contribution in https://github.com/facebook/lexical/pull/9117
- @kavyansh18 made their first contribution in https://github.com/facebook/lexical/pull/9135
- @Dev-next-gen made their first contribution in https://github.com/facebook/lexical/pull/9162
Full Changelog: https://github.com/facebook/lexical/compare/v0.50.0...v0.51.0
v0.50.0
v0.50.0 is a monthly release with a large number of PRs to improve correctness, accessibility, and performance. It also ships HMR support, compiled keyboard shortcut dispatch, and screen reader announcements for headings and auto-links, and build-time tree-shaking annotations (in a new @lexical/compiler package). We have upgraded to pnpm 11, so if you're working directly with the monorepo you will need to upgrade as well.
lexical—LexicalNode.replace()no longer re-homes a named slot value. A slot value has no parent (its up-link is__slotHost), so replacing one through the tree API now fails with an actionable invariant instead of a generic parent error; use$setSloton the owning host.$setBlocksTypeand the block converters skip slot values for the same reason (#8938, #8905, #8901)@lexical/clipboard— The Lexical JSON clipboard payload (application/x-lexical-editor) now asksexcludeFromCopy('clone')instead of'html', matching the destination the rest of that payload already uses. Nodes that opt out of HTML export but expect to survive a clone (e.g.MarkNode) are copied again; customexcludeFromCopyimplementations that keyed on'html'for this channel should be updated (#8995)
These were merged as bug fixes rather than breaking changes, but they change observable output — check them if you snapshot HTML, assert on the DOM, or depend on the old editing behavior.
- HTML export emits a terminating
<br>. A trailingLineBreakNodein a block now exports an extra<br data-lexical-managed-linebreak="true">, mirroring what the reconciler already puts in the live DOM, so<p>a<br></p>survives an export/import round trip. Both importers drop the marker, but exported-HTML fixtures will differ (#8765) - Rich text mounts an
aria-liveregion by default.HeadingAnnounceExtension(viaRichTextExtension) andAutoLinkAnnounceExtension(viaAutoLinkExtension) depend onAriaLiveRegionExtension, which appends a live-region<div>todocument.body— or to the configuredownerelement. Opt out withconfigExtension(HeadingAnnounceExtension, {disabled: true})(#8908, #9071) - Select-all delete and cut now remove the blocks. A whole-document range is widened to the top-level blocks, so the editor is left on a fresh empty paragraph instead of an emptied heading, quote or list that went on styling the next character typed — and Cmd+X now carries those blocks, so pasting restores them (#8884)
- A formatted paragraph copies as a block.
ParagraphNode.extractWithChildnow keeps a fully-selected paragraph that carries alignment, indent or inline style in the payload as a block, instead of splicing its children in and dropping that formatting. Paragraphs with none of it serialize as before (#9059) importJSONapplies registered node replacements. JSON deserialization builds through$create, so a replacement's class is constructed and itsimportJSONruns; a deprecatedreplacewithoutwithKlassis still applied the old way (#9061, #9090)- Listener return types tightened. Only
RootListenerandEditableListenerare typed to return a cleanup function; returning one from another listener is now a TypeScript error — it was never called (#8990) - Collab and Markdown output shifts.
@lexical/yjsno longer syncs roottextFormat/textStyle(#8940); Markdown import restructures nested mixed-type lists and stores fence metadata in a newmdCodeMetanode state (#8283) - New invariants. Replacing a slot value (#8938), an
insertTextanchor that is not a text node, an emptyKeyboardShortcutMatchkey, and acreateBindingV2getXmlText/getXmlElementthat returns an un-integrated or misnamed type (#6483) now throw instead of failing later
lexical—CAN_UNDO_COMMANDandCAN_REDO_COMMANDare deprecated in favor of thecanUndo/canRedosignals onHistoryExtension. A command only reports a change, so a listener registered after initialization can't read the current value; the signal always holds it (#8918)
@lexical/compiler— New package that injects/* @__PURE__ */annotations and inlines the trivial side-effect-free factories (defineExtension,configExtension,safeCast,createCommand,createState, …) at build time, as a Rollup and Vite plugin. Hand-written annotations on those calls are no longer needed (#9086)@lexical/extension—HMRExtension(withHMRConfig,HMROutput,HotContext) keeps an editor alive across hot module replacement.@lexical/reactgainsLexicalMenuOption,LexicalAutoEmbedPluginUtils,LexicalTypeaheadMenuPluginUtilsandLexicalCollaborationContextUtilsentry points that split values out of component modules so Fast Refresh works — the original exports are unchanged (#8959)lexical/@lexical/extension— Compiled keyboard shortcut dispatch:compileKeyboardShortcuts,CONTROL_OR_ALT,CONTROL_OR_META,CONTROL_OR_OTHER_KEY,keyboardEventMaskForPlatformand theKeyboardShortcut*types in core, plusKeyboardShortcutsExtensionandformatKeyboardShortcutfor declaring named shortcuts and rendering them per platform (#8876)@lexical/rich-text—HeadingAnnounceExtensionannounces heading changes to screen readers, on by default inRichTextExtension;@lexical/link'sAutoLinkAnnounceExtensiondoes the same when typing turns text into a link, on by default withAutoLinkExtension(#8908, #9071)@lexical/list— Opt-inWordListImportExtensionreconstructs list structure from Microsoft Word HTML (MsoListParagraphclasses andmso-listmetadata) on paste (#9082)@lexical/rich-text— NewshouldHandlePasteAsFilesconfig (and exporteddefaultShouldHandlePasteAsFiles, plus an optional third argument toregisterRichText) lets an app decide that pasted files win over the incidentaltext/htmlbrowsers attach when an image is copied. The default is unchanged: files are handled only when the clipboard carries no text content (#8902, #8699)@lexical/yjs—CreateBindingV2Options__EXPERIMENTALallows a custom YjsXmlText, so a Lexical document can live inside a larger shared type (#6483)lexical— New$getSelectionSlotFrame(#9052) and$flushSyncAfterUpdate(#9067) exports;$isBlockFullySelectedmoved into core and is still re-exported from@lexical/utils(#9059);@lexical/tablenow exports theTableCellHeaderStatetype (#9038); JSDoc added across the core exports (#8895)- Performance — Bulk inserts and removals no longer walk the parent's children to compute an offset the selection never reads, which made those operations quadratic (#9108)
Named slots & the node tree
- Line breaks inside a slot insert and delete correctly (#8899); a managed line break is restored in wrapped slot hosts (#9066); reading the parent style of a slot value no longer throws (#8950); a slot-bearing decorator host is deleted correctly at the selection boundary (#8905)
replace()keeps the parent's__sizecorrect when handed a sibling (#8917), andspliceno longer creates a sibling cycle when it re-inserts a node after the range (#8916)
Node state, copy/paste & serialization
- HTML import/export and slot frames carry the whole node state, keeping the HTML and Lexical clipboard payloads in agreement (#9052); copy and insert keep the original node's state (#9059); list operations and DOM import/export keep the node's own state (#9050); inline node transforms keep the node and its DOM in step (#9060); code blocks keep the caret and their own attributes (#9056); blocks pasted after consecutive line breaks are preserved (#8890)
- Nodes keep their own properties across clone, split and export:
EditorState.clone()keeps_parsed(#8989),AutoLinkNode.insertNewAfterkeeps its properties (#8996), a split heading keeps its format and style (#8926), split lists continue numbering from the item's value (#8913), and in the playground the Excalidraw drawing and size survive a clone (#8984), a closed collapsible no longer exports as open (#8994), mention nodes keep their display text (#8999), custom nodes keep the theme classescreateDOMapplied (#9049) and an unparseabledata-lexical-datetimeno longer breaks serialization (#9047)
Selection & editing
- Selection and caret state are correct at block and shadow root boundaries (#9058); the block cursor shows before block decorators regardless of the preceding sibling (#8888); the select-all highlight stays visible next to boundary decorators (#8931);
$extendCaretToRange's focus is a real, flippable position (#8930); Shift+Arrow extends adjacent node selections (#9067); clicking inside a selected node no longer deselects it (#8910) insertNodesno longer leaves an empty paragraph after a block inserted at the end of a paragraph (#9099);insertTextno longer throws when the caret is inside a segmentedTextNode(#9104); Backspace works at a soft line-wrap boundary in Firefox (#9101); Enter on iOS no longer moves the caret past the acceptance boundary (#8941); iPadOS desktop-class user agents are detected (#8909); dropped files are forwarded when the drop point has no caret (#9076); clear-formatting resets the cached selection format (#8889)
Tables & lists
- Table grid indices, cell state and boundary selection fixed (#9054); alignment covers every cell a table selection touches (#9043); inserting a column steps by the visited cell's
colSpan(#8911);importDOMimports thedirattribute (#8914);toggleHeaderStylestays insideTableCellHeaderStates(#9038); thetrackTableMutationObserveris disconnected inremoveListeners(#9074); text cursor placement is reliable when tapping cells on touch devices (#8827) - The stale depth theme class is removed when a list changes depth (#9077); rapid clicks on the same checklist checkbox are no longer throttled (#9102); focus stays in the editor when a press lands on a check list item's label (#9088)
Links, Markdown & HTML
TOGGLE_LINK_COMMAND's object payload no longer discards the configured attributes (#8985);$toggleLinkapplies thetitleattribute for aNodeSelection(#8993);LinkNode/AutoLinkNodegetters read the latest state (#9080); middle-clicked links open in a new tab (#9078); the auto embed menu only opens when a bare link is pasted (#9091); the playground'svalidateUrlno longer accepts a sentence that merely contains a URL (#9097)- Markdown round trips keep fenced code and enclosing blocks intact (#9055); nested mixed-type lists import with the right structure (#8283); a URL containing parentheses imports correctly (#9093); no dangling closing tag when a selection slices a format to whitespace (#8961); no stray leading newline when a selection starts below the first block (#8960)
- A trailing line break survives HTML export and re-import (#8765);
exportDOMreturning aDocumentFragmentapplies itsafter()replacement (#8997);parseSelectorrejects an empty selector group (#9083); Prism language maps are read as own properties (#8981); a function-valued style patch is applied once to an empty element (#8912);objectKlassEqualsno longer throws onundefinedor prototype-less objects (#9079)
React, collaboration & history
- Decorator portals are recreated when the editor root remounts (#8921);
Placeholderuses the SSR-safeuseLayoutEffect(#8906); the typeahead query updates during IME composition (#8942); plugins and hooks re-derive when their inputs change (#9051); focus is restored after dragging decorator blocks (#9064); multiple clicks are normalized (#8928) - Collab sync gaps between the editor state and the Yjs doc are closed, and bootstrapping the initial state no longer becomes an undo entry (#9057); only one client may bootstrap a nested editor's document, so an image caption or sticky note no longer gains a spurious leading paragraph —
shouldBootstrapis documented as at-most-one-client (#9107);SharedHistoryExtensionforwards the parentmaxDepth(#9044) and shared history stacks record the state of the editor that actually changed, alongside fixes to overlays, hit targets and shared state at the editor boundary (#9053)
Docs & tooling
- New Decorators concept guide (#8696), a React MathType example (#8692), a clarified vanilla quick start (#8801), documented
DOMImportExtensionrule evaluation order (#9089),SKIP_DOM_SELECTION_TAGbehavior during the initial editor state (#8636) and$reverseDfs(#8962), plus an OpenGraph social preview for the website (#8935) - Upgraded to pnpm 11 (#8816), cached Playwright's apt packages in CI (#9085), extracted the internal-registry OIDC exchange into a reusable action (#9084), fixed a
qsdependency vulnerability (#9072), quieted stderr noise intest-unit(#9098) and moved the playground ontoownerDocument/$getDocument()for shadow DOM safety (#8878)
- v0.49.0 by @etrepum in https://github.com/facebook/lexical/pull/8893
- [lexical-playground] Chore: Use ownerDocument and $getDocument() for shadow DOM safety by @mayrang in https://github.com/facebook/lexical/pull/8878
- [lexical] Documentation Update: Add JSDoc comments to core package exports by @mayrang in https://github.com/facebook/lexical/pull/8895
- [lexical][lexical-rich-text] Bug Fix: Show block cursor before block decorators regardless of preceding sibling by @ochevallier in https://github.com/facebook/lexical/pull/8888
- [lexical] Bug Fix: Line breaks in a slot can't be inserted or deleted correctly by @sahiee-dev in https://github.com/facebook/lexical/pull/8899
- [lexical-playground] Bug Fix: Reset the cached selection format on clear formatting by @Yjason-K in https://github.com/facebook/lexical/pull/8889
- [lexical-selection] Bug Fix: Handle bare slot values in $setBlocksType by @mayrang in https://github.com/facebook/lexical/pull/8901
- [lexical-react] Bug Fix: Use the SSR-safe useLayoutEffect in Placeholder by @arcs- in https://github.com/facebook/lexical/pull/8906
- [lexical][lexical-selection][lexical-list] Bug Fix: Skip named-slot values in block converters, diagnose replace() on a slot value, and delete slot-bearing decorator hosts at the selection boundary by @etrepum in https://github.com/facebook/lexical/pull/8905
- [lexical-extension] Bug Fix: Normalize multiple clicks by @levensta in https://github.com/facebook/lexical/pull/8928
- [lexical-rich-text] Feat: add pasteFileContentCheck config to let files win over incidental HTML on paste by @Sa-Te in https://github.com/facebook/lexical/pull/8902
- [lexical] Bug Fix: Detect iPadOS desktop-class user agents by @corinthionia in https://github.com/facebook/lexical/pull/8909
- [lexical-rich-text] Bug Fix: Don't deselect a selected node when clicking inside it by @alvorithm in https://github.com/facebook/lexical/pull/8910
- [lexical-table] Bug Fix: step by the visited cell's colSpan when walking left to insert a column by @LeSingh1 in https://github.com/facebook/lexical/pull/8911
- [lexical-selection] Bug Fix: apply a function-valued style patch only once to an empty element by @LeSingh1 in https://github.com/facebook/lexical/pull/8912
- [lexical-table] Bug Fix: Import the dir attribute in table importDOM by @LeSingh1 in https://github.com/facebook/lexical/pull/8914
- [lexical-react] Bug Fix: Recreate decorator portals when the editor root remounts by @alphanull in https://github.com/facebook/lexical/pull/8921
- [lexical] Bug Fix: keep parent __size correct when replace() is passed a sibling by @LeSingh1 in https://github.com/facebook/lexical/pull/8917
- [lexical] Bug Fix: don't create a sibling cycle when splice re-inserts the node after the range by @LeSingh1 in https://github.com/facebook/lexical/pull/8916
- [lexical-rich-text] Bug Fix: preserve heading format and style when splitting a heading by @LeSingh1 in https://github.com/facebook/lexical/pull/8926
- [lexical-list] Bug Fix: continue split-list numbering from the item's value, not its index by @LeSingh1 in https://github.com/facebook/lexical/pull/8913
- [lexical] Bug Fix: make $extendCaretToRange's focus a real, flippable position by @Sa-Te in https://github.com/facebook/lexical/pull/8930
- [lexical] Deprecate CAN_UNDO_COMMAND and CAN_REDO_COMMAND in favour of HistoryExtension's signals by @LeSingh1 in https://github.com/facebook/lexical/pull/8918
- [lexical-website] Add opengraph social preview image by @alex-js-ltd in https://github.com/facebook/lexical/pull/8935
- [Breaking Change][lexical][lexical-utils][lexical-selection][lexical-website] Bug Fix: LexicalNode.replace no longer re-homes named slots by @etrepum in https://github.com/facebook/lexical/pull/8938
- [lexical-playground] Chore: Stabilize the collab dangling-text e2e tests by @etrepum in https://github.com/facebook/lexical/pull/8933
- [scripts] Bug Fix: wait out minimumReleaseAge boundary in example installs by @etrepum in https://github.com/facebook/lexical/pull/8934
- [lexical-yjs] Bug Fix: Don't sync root textFormat/textStyle by @patrick-atticus in https://github.com/facebook/lexical/pull/8940
- [lexical-react] Bug Fix: Update the typeahead query during IME composition by @hamo-o in https://github.com/facebook/lexical/pull/8942
- [lexical-selection] Bug Fix: don't throw reading the parent style of a slot value by @LeSingh1 in https://github.com/facebook/lexical/pull/8950
- [lexical-utils] Documentation Update: describe $reverseDfs instead of $reverseDfsIterator by @luantaraschi in https://github.com/facebook/lexical/pull/8962
- [lexical][lexical-website] Documentation Update: SKIP_DOM_SELECTION_TAG is ignored during initial editor state by @spokodev in https://github.com/facebook/lexical/pull/8636
- [lexical] Bug Fix: keep the select-all highlight visible next to boundary decorators by @etrepum in https://github.com/facebook/lexical/pull/8931
- [lexical-markdown] Bug Fix: don't emit a dangling closing tag when a selection slices a format to whitespace by @luantaraschi in https://github.com/facebook/lexical/pull/8961
- [lexical-code-prism] Bug Fix: read the language maps as own properties by @luantaraschi in https://github.com/facebook/lexical/pull/8981
- [lexical] Bug Fix: Don't move the caret past the acceptance boundary for Enter on iOS by @SujinKim1127 in https://github.com/facebook/lexical/pull/8941
- [lexical-playground] Bug Fix: keep the Excalidraw drawing and its size across a node clone by @LeSingh1 in https://github.com/facebook/lexical/pull/8984
- [lexical-link] Bug Fix: TOGGLE_LINK_COMMAND object payload no longer discards the configured attributes by @LeSingh1 in https://github.com/facebook/lexical/pull/8985
- [lexical] Bug Fix: EditorState.clone() keeps the _parsed flag by @LeSingh1 in https://github.com/facebook/lexical/pull/8989
- [lexical] Bug Fix: only root and editable listeners may return a cleanup function by @LeSingh1 in https://github.com/facebook/lexical/pull/8990
- [lexical-link] Bug Fix: $toggleLink applies the title attribute for a NodeSelection by @LeSingh1 in https://github.com/facebook/lexical/pull/8993
- [lexical-playground] Bug Fix: $createMentionNode keeps the display text it is given by @LeSingh1 in https://github.com/facebook/lexical/pull/8999
- [lexical-playground] Bug Fix: a closed collapsible container no longer exports as open by @LeSingh1 in https://github.com/facebook/lexical/pull/8994
- [Breaking Change][lexical-clipboard] Bug Fix: the Lexical clipboard payload asks excludeFromCopy for the clone destination by @LeSingh1 in https://github.com/facebook/lexical/pull/8995
- [lexical-link] Bug Fix: AutoLinkNode.insertNewAfter keeps the node's own properties by @LeSingh1 in https://github.com/facebook/lexical/pull/8996
- [lexical-html] Bug Fix: apply the after() replacement when exportDOM returns a DocumentFragment by @LeSingh1 in https://github.com/facebook/lexical/pull/8997
- [lexical-table] Bug Fix: align every cell a table selection covers, not just the naive rect by @LeSingh1 in https://github.com/facebook/lexical/pull/9043
- [lexical-playground] Bug Fix: importing an unparseable data-lexical-datetime no longer breaks serialization by @LeSingh1 in https://github.com/facebook/lexical/pull/9047
- [lexical-history] Bug Fix: SharedHistoryExtension forwards the parent maxDepth by @LeSingh1 in https://github.com/facebook/lexical/pull/9044
- [lexical-table] Bug Fix: toggleHeaderStyle stays inside TableCellHeaderStates by @LeSingh1 in https://github.com/facebook/lexical/pull/9038
- [lexical] Bug fix: apply nodes replacement for importJSON by @fantactuka in https://github.com/facebook/lexical/pull/9061
- [lexical-text][lexical-mark][lexical-link][lexical-playground] Bug Fix: inline node transforms keep the node and its DOM in step by @LeSingh1 in https://github.com/facebook/lexical/pull/9060
- [lexical-rich-text][lexical-a11y] Feature: Announce heading changes by default in rich text by @Electro-Jam in https://github.com/facebook/lexical/pull/8908
- [lexical-react][lexical-playground] Bug Fix: restore focus after dragging decorator blocks by @luantaraschi in https://github.com/facebook/lexical/pull/9064
- [lexical][lexical-extension][lexical-playground] Refactor: Compiled keyboard shortcut dispatch by @mayrang in https://github.com/facebook/lexical/pull/8876
- [lexical] Bug Fix: restore managed line break in wrapped slot hosts by @luantaraschi in https://github.com/facebook/lexical/pull/9066
- build(deps): bump mermaid from 11.15.0 to 11.16.1 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8980
- [lexical-rich-text] Bug Fix: extend adjacent node selections with Shift+Arrow by @luantaraschi in https://github.com/facebook/lexical/pull/9067
- [lexical] Chore: Fix qs package dependency vulnerability by @vijayojha89 in https://github.com/facebook/lexical/pull/9072
- [lexical-website] Documentation Update: Add Decorators concept guide by @WilliamK112 in https://github.com/facebook/lexical/pull/8696
- [lexical-markdown] Bug Fix: don't prefix a newline when a selection starts below the first block by @luantaraschi in https://github.com/facebook/lexical/pull/8960
- [lexical-table] Bug Fix: disconnect trackTable MutationObserver in removeListeners by @kaminski-dev in https://github.com/facebook/lexical/pull/9074
- [lexical-utils] Bug Fix: objectKlassEquals throws on undefined and prototype-less objects by @nithin42 in https://github.com/facebook/lexical/pull/9079
- [lexical-html] Bug Fix: reject an empty selector group in parseSelector by @luantaraschi in https://github.com/facebook/lexical/pull/9083
- [lexical-list] Feature: opt-in Word list paste overlay by @smrifat1411 in https://github.com/facebook/lexical/pull/9082
- [lexical-link] Bug Fix: read the latest state in LinkNode and AutoLinkNode getters by @nithin42 in https://github.com/facebook/lexical/pull/9080
- [lexical-list] Bug Fix: remove the stale depth theme class when a list changes depth by @nithin42 in https://github.com/facebook/lexical/pull/9077
- [ci] Extract the internal-registry OIDC exchange into a reusable auth action by @zurfyx in https://github.com/facebook/lexical/pull/9084
- [lexical-link] Feature: Tell screen reader users when typing turns text into a link by @Electro-Jam in https://github.com/facebook/lexical/pull/9071
- [ci] Chore: cache Playwright's apt packages and skip WebKit deps on Linux by @etrepum in https://github.com/facebook/lexical/pull/9085
- docs: clarify vanilla quick start path by @alexespinoza28 in https://github.com/facebook/lexical/pull/8801
- [lexical-html][lexical-rich-text][lexical-website] Docs: clarify DOMImportExtension rule evaluation order by @etrepum in https://github.com/facebook/lexical/pull/9089
- [lexical] Feature: build the node with $create when importing JSON by @etrepum in https://github.com/facebook/lexical/pull/9090
- [lexical-code-core][lexical-code-prism][lexical-code-shiki] Bug Fix: code blocks keep the caret and their own attributes by @LeSingh1 in https://github.com/facebook/lexical/pull/9056
- [lexical-compiler][lexical-eslint-plugin-internal] Feature: inject /* @PURE */ annotations at build time by @etrepum in https://github.com/facebook/lexical/pull/9086
- [lexical-playground] Bug Fix: validateUrl no longer accepts a sentence that merely contains a URL by @Om-singhaI in https://github.com/facebook/lexical/pull/9097
- [lexical-markdown] Bug Fix: import a link whose URL contains parentheses by @luantaraschi in https://github.com/facebook/lexical/pull/9093
- [tests] Chore: silence unnecessary stderr warnings in test-unit by @etrepum in https://github.com/facebook/lexical/pull/9098
- [lexical] Bug Fix: Backspace at a soft line-wrap boundary in Firefox by @etrepum in https://github.com/facebook/lexical/pull/9101
- [lexical] Bug Fix: insertNodes no longer leaves an empty paragraph after a block inserted at the end of a paragraph by @Om-singhaI in https://github.com/facebook/lexical/pull/9099
- [lexical-list] Bug Fix: stop throttling rapid mouse clicks on the same checklist checkbox by @noeschmidt in https://github.com/facebook/lexical/pull/9102
- [lexical-react] Bug Fix: Only open the auto embed menu when a bare link is pasted by @Om-singhaI in https://github.com/facebook/lexical/pull/9091
- [lexical-history][lexical-utils][lexical-playground] Bug Fix: overlays, hit targets and shared state at the editor boundary by @LeSingh1 in https://github.com/facebook/lexical/pull/9053
- [lexical-playground] Bug Fix: custom nodes keep the theme classes createDOM applied by @LeSingh1 in https://github.com/facebook/lexical/pull/9049
- [lexical] Bug Fix: insertText no longer throws when the caret is inside a segmented TextNode by @Om-singhaI in https://github.com/facebook/lexical/pull/9104
- [lexical][lexical-rich-text][lexical-utils] Bug Fix: copy and insert keep the original node's state by @LeSingh1 in https://github.com/facebook/lexical/pull/9059
- [lexical-list] Bug Fix: list operations and DOM import/export keep the node's own state by @LeSingh1 in https://github.com/facebook/lexical/pull/9050
- [lexical-rich-text] Bug Fix: forward dropped files when the drop point has no caret by @nithin42 in https://github.com/facebook/lexical/pull/9076
- [lexical-list][lexical-playground] Bug Fix: keep the focus on the editor when a press lands in a check list item's label by @luantaraschi in https://github.com/facebook/lexical/pull/9088
- [lexical-utils] Bug Fix: Prioritize file transfer over text/html when pasting browser-copied images by @VivekJariwala50 in https://github.com/facebook/lexical/pull/8699
- [lexical][lexical-html][lexical-clipboard] Bug Fix: HTML import/export and slot frames carry the whole state by @LeSingh1 in https://github.com/facebook/lexical/pull/9052
- [lexical-yjs][lexical-react] Bug Fix: collab sync gaps between the editor state and the yjs doc by @LeSingh1 in https://github.com/facebook/lexical/pull/9057
- [lexical-link] Bug Fix: open middle-clicked links in a new tab by @nithin42 in https://github.com/facebook/lexical/pull/9078
- [lexical-table][lexical-playground][lexical-rich-text] Bug Fix: table grid indices, cell state and boundary selection by @LeSingh1 in https://github.com/facebook/lexical/pull/9054
- [lexical][lexical-table] Bug Fix: selection and caret state at block and shadow-root boundaries by @LeSingh1 in https://github.com/facebook/lexical/pull/9058
- [lexical-react][lexical-playground] Bug Fix: plugins and hooks re-derive when their inputs change by @LeSingh1 in https://github.com/facebook/lexical/pull/9051
- [lexical-markdown][lexical-mdast] Bug Fix: markdown round trip keeps fenced code and enclosing blocks intact by @LeSingh1 in https://github.com/facebook/lexical/pull/9055
- Add React MathType example by @culpen90 in https://github.com/facebook/lexical/pull/8692
- [lexical-table] Bug Fix: Fix unreliable text cursor placement when tapping table cells on touch devices by @Arman-Luthra in https://github.com/facebook/lexical/pull/8827
- [lexical-yjs][lexical-react] Feature: Allow custom Yjs XmlText by @flaviouk in https://github.com/facebook/lexical/pull/6483
- Upgrade to pnpm 11 by @zurfyx in https://github.com/facebook/lexical/pull/8816
- @Yjason-K made their first contribution in https://github.com/facebook/lexical/pull/8889
- @arcs- made their first contribution in https://github.com/facebook/lexical/pull/8906
- @corinthionia made their first contribution in https://github.com/facebook/lexical/pull/8909
- @alvorithm made their first contribution in https://github.com/facebook/lexical/pull/8910
- @alphanull made their first contribution in https://github.com/facebook/lexical/pull/8921
- @alex-js-ltd made their first contribution in https://github.com/facebook/lexical/pull/8935
- @luantaraschi made their first contribution in https://github.com/facebook/lexical/pull/8962
- @spokodev made their first contribution in https://github.com/facebook/lexical/pull/8636
- @SujinKim1127 made their first contribution in https://github.com/facebook/lexical/pull/8941
- @Electro-Jam made their first contribution in https://github.com/facebook/lexical/pull/8908
- @WilliamK112 made their first contribution in https://github.com/facebook/lexical/pull/8696
- @kaminski-dev made their first contribution in https://github.com/facebook/lexical/pull/9074
- @nithin42 made their first contribution in https://github.com/facebook/lexical/pull/9079
- @smrifat1411 made their first contribution in https://github.com/facebook/lexical/pull/9082
- @alexespinoza28 made their first contribution in https://github.com/facebook/lexical/pull/8801
- @Om-singhaI made their first contribution in https://github.com/facebook/lexical/pull/9097
- @noeschmidt made their first contribution in https://github.com/facebook/lexical/pull/9102
- @VivekJariwala50 made their first contribution in https://github.com/facebook/lexical/pull/8699
- @culpen90 made their first contribution in https://github.com/facebook/lexical/pull/8692
- @Arman-Luthra made their first contribution in https://github.com/facebook/lexical/pull/8827
- @flaviouk made their first contribution in https://github.com/facebook/lexical/pull/6483
Full Changelog: https://github.com/facebook/lexical/compare/v0.49.0...v0.50.0
v0.49.0
v0.49.0 is a maintenance release headlined by the completion of the $config() protocol migration for Lexical's built-in node classes (#8640), a breaking change that replaces per-node getType()/clone()/importJSON()/importDOM()/transform() boilerplate with runtime-synthesized behavior. It ships with a cluster of follow-up fixes hardening the synthesized getType() and clone() (including a stack overflow in compiled builds), an opt-in sticky horizontal scrollbar for overflowing tables, and a broad batch of fixes across tables, Markdown, HTML, code highlighting, and selection.
lexical— Built-in node classes are ported to the$config()protocol. The staticimportJSON(),importDOM(),clone(), andtransform()methods are no longer present on ported nodes; use the higher-level equivalents instead (LexicalEditor.parseEditorState/$generateNodesFromDOM, the$cloneWithPropertieshelper, and extensions or$transformin$config).getType()is unchanged and safe to keep using,__typeis nowreadonly, and node constructors require zero-argument defaults. Custom nodes may keep their static methods, but adopting$config()is recommended (#8640)lexical—LexicalCommand<T>'s payload type is now invariant to prevent unsafe structural compatibility between commands. Previously correct code (including explicit generics) needs no changes; only unsafeLexicalCommand<unknown>usage must switch to the newly exportedAnyLexicalCommandalias.dispatchCommand's payload argument is now optional when a command's payload type isundefinedorvoid, and redundant explicit type parameters were dropped from theregisterCommand/registerNodeTransformcall sites (#8877)
@lexical/table— Opt-in sticky horizontal scrollbar for tables wider than their container, so the scrollbar stays anchored at the viewport bottom instead of only being reachable at the end of the table. Enable it withhasStickyScrollbar: truein the table config; style it via the newtableStickyScrollbartheme key (#8790)@lexical/table— The<colgroup>element is now omitted from the table DOM when column widths are undefined, producing cleaner markup and letting the browser auto-size columns; it is created or removed dynamically as widths change (#8850)lexical— Added an editor operation benchmark suite (paragraph split, bold formatting, range deletion, paste, select-all format) measured through full DOM reconciliation, to help contributors track core editing performance (#8856)
@lexical/table—$createTableSelectionis deprecated in favor of$createTableSelectionFrom, which takes the table node plus anchor/focus cells and validates them, instead of returning a blank selection with placeholder'root'keys that must be overwritten (#8855)@lexical/table—getShape()is deprecated because it computes incorrect bounds for merged cells; use the now-exported$computeTableCellRectBoundary(with$computeTableMap) instead (#8853)
$config() follow-ups (#8640)
- The synthesized
clone()now appliesafterCloneFrom()when called directly (e.g.NodeClass.clone(node)), fixing silent property loss across 25+ core nodes (#8864) - The synthesized
getType()no longer returns the superclass type when inherited, fixing node-type collisions during editor registration (#8867) - The synthesized
getType()no longer recurses infinitely when a bundler copies it onto a subclass as an own static, fixing stack overflows in compiled/minified builds (#8869)
Tables
DELETE_LINE_COMMAND(Cmd/Ctrl-based delete-line shortcuts) now works inside table cells instead of being silently swallowed (#8851)- Table alignment now works when cells are selected in any direction, not just top-left→bottom-right (#8883)
Selection & editing
- Editor updates dispatched from a read-only context (e.g. inside
editor.read()) now run in a fresh writable update instead of being silently dropped, with a dev warning (#8863) - Firefox now creates a selection and shows the block cursor when clicking in the gap between block decorators (#8862)
- Pressing ArrowUp before a leading non-inline decorator no longer moves the selection out of the editor (#8887)
Markdown, HTML & code
- Typing a list marker at the start of a heading no longer converts the heading into a list (#8879)
- HTML import now evaluates unrestricted CSS selector groups (e.g.
p, .foo) against all elements instead of only tag-matched ones (#8873) - Concurrent async language/theme loads in the Shiki highlighter are deduplicated and merged into a single history entry, avoiding spurious undo states (#8854)
QuoteNode.updateDOMnow accepts theEditorConfigargument the reconciler passes to every other node, for API consistency (#8882)
Playground & website
- Playground scroll padding now accounts for the sticky toolbar so selections scrolled into view from above aren't hidden behind it (#8849)
- Fixed a homepage crash caused by a minified dev build, and isolated each embedded example in its own error boundary so one failure no longer takes down the page (#8861)
- [lexical] Bug Fix: Scope bench vitest projects to exclude regular test files by @mayrang in #8852
- [lexical-table] Bug Fix: Enable DELETE_LINE_COMMAND in table cells by @mayrang in #8851
- [lexical-table] Chore: Deprecate $createTableSelection in favor of $createTableSelectionFrom by @mayrang in #8855
- [Breaking Changes][lexical] Refactor: Port node classes to the $config() protocol by @etrepum in #8640
- [lexical-playground] Bug Fix: account for sticky toolbar in scroll padding by @etrepum in #8849
- [lexical-list] Chore: Rename isNestedListNode to $isNestedListNode by @etrepum in #8843
- [lexical-table][lexical-playground] Chore: Deprecate getShape() and migrate playground by @mayrang in #8853
- [lexical-table] Chore: Remove dead code in table command handlers by @mayrang in #8857
- [lexical-code-shiki] Bug Fix: Deduplicate async loads and merge into history by @Alxs39 in #8854
- [lexical-table][lexical] Feature: Sticky scrollbar for overflowing tables by @mayrang in #8790
- fix: $config() auto-synthesized clone() loses properties when called directly (#8640) by @potatowagon in #8864
- fix: $config() synthesized getType() inherited by subclasses causes node-type collision (#8640) by @potatowagon in #8867
- [lexical] Chore: Migrate LexicalSelection tests to buildEditorFromExtensions by @mayrang in #8865
- [lexical] Feature: Editor operation benchmarks by @mayrang in #8856
- [lexical] Bug Fix: run editor updates dispatched from a read-only context in a fresh writable update by @potatowagon in #8863
- [lexical][lexical-website] Bug Fix: Homepage crash from optimized dev build by @etrepum in #8861
- fix: $config() synthesized getType() recurses infinitely when inherited as own static (#8867 follow-up) by @potatowagon in #8869
- [lexical] Bug Fix: Create selection when clicking between block decorators on Firefox by @mayrang in #8862
- [lexical-table] Feature: Skip colgroup element in table DOM with undefined col widths by @zacharyg-qualtrics in #8850
- [lexical-list] Chore: Remove redundant decorator-adjacent backspace handler by @mayrang in #8871
- [lexical] Refactor: Simplify RangeSelection.insertText via removeText decomposition by @mayrang in #8870
- [lexical] Performance: Skip redundant selection restoration in $removeTextFromCaretRange by @mayrang in #8872
- [lexical-playground] Bug Fix: Deterministic history coalescing for flaky webkit undo tests by @etrepum in #8874
- [lexical-html] Bug Fix: Dispatch unrestricted CSS selector groups by @winklemad in #8873
- [Breaking Change][lexical] Chore: Remove redundant registerCommand/registerNodeTransform generics by @mayrang in #8877
- [lexical-table] Bug Fix: Table alignment fails when selecting in non-TL->BR direction by @sahiee-dev in #8883
- [lexical-rich-text] Bug Fix: Forward editorConfig to QuoteNode.updateDOM by @werterhalimi in #8882
- [lexical-markdown] Bug Fix: Preserve headings when typing list shortcuts by @StevenPDang in #8879
- [lexical-rich-text] Bug Fix: Keep block cursor in editor when ArrowUp at start of root (#8886) by @etrepum in #8887
- @Alxs39 made their first contribution in #8854
- @zacharyg-qualtrics made their first contribution in #8850
- @winklemad made their first contribution in #8873
- @werterhalimi made their first contribution in #8882
- @StevenPDang made their first contribution in #8879
Full Changelog: v0.48.0...v0.49.0
v0.48.0
v0.48.0 is a maintenance release focused on bug fixes across Markdown, tables, lists, links, and selection. It's headlined by a fix for a v0.46.0 regression that broke native text drag-and-drop (#8842) and a couple of notable security hardening fixes. It also adds a handful of new features, including an MdastHtmlExtension with examples for authoring custom Markdown constructs (collapsibles, kbd, alerts, footnotes), a customizable Yjs shared-type root name for collaborative editing, and new table row manipulation helpers.
@lexical/table— Added$moveTableRowfor reordering table rows, plus the previously missing$unmergeCellNodeexport (#8833)@lexical/yjs/@lexical/react— The Yjs shared-type root name is now customizable, so Lexical can share a Yjs document with other content that uses a different root key (#8841)@lexical/extension/@lexical/mdast— AddedMdastHtmlExtensionand Markdown custom-construct examples (collapsible sections,kbd, alerts, footnotes) demonstrating how to extend the Markdown ↔ mdast pipeline. See the Markdown & mdast serialization guide (#8826)
Drag & drop (fix for v0.46.0 regression)
- Don't cancel
dragoverfor text drags, so native drops work again (#8842)
Security
LinkNode.sanitizeUrl()now fails closed on unparseable URLs, preventing a potential XSS vector (#8846)- Fixed a
serialize-javascriptdependency vulnerability (#8803)
Markdown & code
- Roundtrip overlapping inline formats correctly through mdast/Markdown (#8825)
- Force re-tokenization after an async language load so highlighting appears once the grammar is ready (#8830)
Tables
- Auto-scroll while drag-selecting cells past the visible edge (#8822)
- Enable table copy in read-only mode (#8845)
Lists & character limit
- Backspace at the start of a list item now outdents or converts to a paragraph (#8829)
- Merge adjacent
OverflowNodes inuseCharacterLimit(#8831) - Count block separators when wrapping character-limit overflow (#8840)
Links & selection
- Disable link opening for disabled autolinks (#8839)
- Skip
scrollIntoViewIfNeededwhen the selection rect is above the editor, fixing a Safari RTL caret jump (#8848)
- [lexical-mdast][lexical-markdown] Bug Fix: Roundtrip overlapping inline formats by @etrepum in https://github.com/facebook/lexical/pull/8825
- [lexical-table][lexical-playground] Bug Fix: Auto-scroll while drag-selecting cells past the visible edge by @JohnJunior in https://github.com/facebook/lexical/pull/8822
- [lexical-code-shiki] Bug Fix: force re-tokenize after async language load by @ochevallier in https://github.com/facebook/lexical/pull/8830
- [lexical-react] Bug Fix: Merge adjacent OverflowNodes in useCharacterLimit by @mayrang in https://github.com/facebook/lexical/pull/8831
- Open playground links in a new tab by @potatowagon in https://github.com/facebook/lexical/pull/8837
- [lexical-rich-text][lexical-plain-text] Bug Fix: don't cancel dragover for text drags so native drops work again by @etrepum in https://github.com/facebook/lexical/pull/8842
- [lexical-link] Bug Fix: disable link opening for disabled autolink in… by @ochevallier in https://github.com/facebook/lexical/pull/8839
- [lexical-table] Feature: Add $moveTableRow function & Add missing export for $unmergeCellNode by @hamo-o in https://github.com/facebook/lexical/pull/8833
- [lexical-list] Bug Fix: Backspace at start of list item outdents or converts to paragraph by @mayrang in https://github.com/facebook/lexical/pull/8829
- [lexical-yjs][lexical-react] Feature: Customizable Yjs shared-type root name by @mayrang in https://github.com/facebook/lexical/pull/8841
- [lexical] Chore: Fix serialize-javascript package dependency vulnerability by @vijayojha89 in https://github.com/facebook/lexical/pull/8803
- [lexical-react] Bug Fix: Count block separators in character limit overflow wrapping by @mayrang in https://github.com/facebook/lexical/pull/8840
- Fix: fail closed in LinkNode.sanitizeUrl() on unparseable URLs (XSS) by @xiezhenjia-meta in https://github.com/facebook/lexical/pull/8846
- [lexical-extension][lexical-mdast][dev-mdast-editor-example] Feature: Add MdastHtmlExtension and Markdown custom-construct examples (collapsible, kbd, alerts, footnotes) by @etrepum in https://github.com/facebook/lexical/pull/8826
- [lexical-react][lexical-table] Bug Fix: Enable table copy in read-only mode by @mayrang in https://github.com/facebook/lexical/pull/8845
- Skip scrollIntoViewIfNeeded when the selection rect is above the editor (Safari RTL caret jump) by @jeremy in https://github.com/facebook/lexical/pull/8848
- @JohnJunior made their first contribution in https://github.com/facebook/lexical/pull/8822
- @jeremy made their first contribution in https://github.com/facebook/lexical/pull/8848
Full Changelog: https://github.com/facebook/lexical/compare/v0.47.0...v0.48.0
v0.47.0
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.
@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.
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)
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)
- [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
- @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: https://github.com/facebook/lexical/compare/v0.46.0...v0.47.0
v0.46.0
v0.46.0 is a monthly release headlined by two major new experimental capabilities:
- Named slots - a model that lets a single host element or decorator node own several isolated editable regions inside the host's own
editorState - Shadow DOM - the root element can now be hosted in an open shadow root (or iframe)
This release also includes many other fixes and new features across IME/composition, collaboration, markdown round-tripping, lists, code blocks, links, and mobile keyboards. It is also our first release (other than nightlies) to use NPM Trusted Publishing.
Special recognition for this release goes to @mayrang for doing the majority of the work on both of these new features as well as fixing some tricky IME/composition issues 👏 @levensta has also been doing a fantastic job going through the issue backlog, providing valuable feedback on these bleeding edge features, and identifying long-standing edge cases.
The zero-argument generics on getParent(OrThrow), getPreviousSibling(s), getNextSibling(s), getChildren, getFirstChild(OrThrow), getLastChild(OrThrow), getChildAtIndex, getFirstDescendant, getLastDescendant, and getDescendantByIndex were implicit unchecked casts — there is no inference site, so any non-base type argument was equivalent to an as cast. Each method is now an overload pair: a documented non-generic signature returning the base type (LexicalNode / ElementNode | null), plus the old generic signature marked @deprecated. Code that leaned on contextual-type inference no longer type-checks:
// Before: compiled (unsound). After: type error.
const node: ParagraphNode | null = $getRoot().getFirstChild();
// Port directly with an explicit cast (no behavior change):
const node = $getRoot().getFirstChild() as ParagraphNode | null;
// Or, better, narrow with a guard:
const node = $getRoot().getFirstChild();
if ($isParagraphNode(node)) { /* node: ParagraphNode */ }
Existing getFirstChild<ParagraphNode>()-style calls still compile but are now deprecated and will be removed in a future release. This is a types-only change with no runtime impact.
The "selection captured outside of Lexical" mechanism is generalized beyond DecoratorNode subtrees: setDOMUnmanaged(dom, {captureSelection: true}) now marks any subtree (e.g. a DOMRenderExtension override or a getDOMSlot widget) as selection-captured, and isDOMCapturingSelection(dom) walks ancestors so a descendant <input> reports as captured. As part of this, the root element now carries a __lexicalKey_* stash, so $getNodeFromDOM / $getNearestNodeFromDOMNode resolve the root element to the RootNode instead of null. Two call sites become more correct (drop-on-root in clipboard, table-selection→range conversion), but external callers that relied on $getNearestNodeFromDOMNode(rootElement) returning null must update. The internal-only $isSelectionCapturedInDecorator was removed.
RangeSelection.insertNodes now preserves the first LineBreakNode when inserting inline content ahead of a block element, instead of silently dropping it. Separately, the reconciler-inserted "managed" line breaks (the otherwise-invisible <br>s Lexical adds so the caret can land in empty lines) are now identifiable in the DOM as <br data-lexical-managed-linebreak="true"> — and, on iOS Safari, an analogous <img data-lexical-managed-linebreak="true" …> in some cases. DOM/HTML snapshot test expectations may need to ignore or expect this attribute. Closes #3980.
@lexical/html and node extensions — DOMImportExtension rules now register implicitly (#8662) (experimental)
The experimental DOM-import pipeline no longer requires you to list a per-package import extension. Each node-providing extension (RichTextExtension, ListExtension, LinkExtension, TableExtension, CodeExtension) now registers its own import rules, and the standalone RichTextImportExtension / ListImportExtension / LinkImportExtension / TableImportExtension / CodeImportExtension / HorizontalRuleImportExtension become deprecated aliases that may be removed as early as v0.47.0. Rules stay inert unless HTML is routed through ClipboardDOMImportExtension or $generateNodesFromDOMViaExtension; the legacy importDOM paste path is unchanged. If you had not adopted these v0.45.0 extensions yet, there is no breaking change.
All slot machinery is opt-in and gated (an editor latches _slotsUsed on the first $setSlot), so editors that never use slots take identical code paths to before. Two changes are observable regardless:
syncLexicalUpdateToYjsV2__EXPERIMENTALtakes a newdirtyLeavesparameter, inserted betweendirtyElementsandnormalizedNodes(a slot host's values surface as dirty leaves).- A
NodeSelectioncontaining anElementNodenow includes that element's children on copy/export ($getHtmlContent/$generateJSONFromSelectedNodes). The previous behavior serialized a childless shell, making cut of an elementNodeSelectionsilently lossy; partialRangeSelections keep per-child slicing andexcludeFromCopychildren remain excluded.
Exports marked @deprecated in v0.32.1 (2025-06-04, >12 months ago) with no Meta-internal consumers are removed:
@lexical/link:toggleLink→ use$toggleLink@lexical/list:insertList/removeList→ use$insertList/$removeList(from an update or command listener)@lexical/react: theContentEditablePropstype alias → useContentEditableProps
Note: lexical's $nodesOfType is intentionally un-deprecated (it still has many consumers). The remaining v0.32.1 deprecations that still have internal consumers (KEY_MODIFIER_COMMAND, $wrapNodes, the @lexical/table row/column helpers, etc.) are left for a follow-up.
read gains an optional first argument: 'force-commit' (the default; flushes pending updates first — the previous one-argument behavior), 'pending' (reads the pending state without flushing — the old editor.readPending, now removed), and 'latest' (reads the committed state without flushing, equivalent to editor.getEditorState().read(fn, {editor})). EditorReadMode is exported. readPending only shipped after v0.45.0, so its removal is not considered a breaking change.
An editor can now mount inside an open shadow tree without losing selection, focus, drag-and-drop, IME composition, or floating-UI behavior. Reads go through platform APIs — Selection.getComposedRanges, Selection.direction, ShadowRoot.activeElement, Document.caretPositionFromPoint(x, y, {shadowRoots}) — and nine new helpers ship from lexical; the light-DOM code paths are unchanged. Follow-ups #8708 (insert nodes at the block cursor inside a shadow root) and #8740 (ignore beforeinput/input in captured decorators, fixing Firefox 152) complete the surface.
CreateEditorArgs gains an optional onWarn?: ErrorHandler (stored as _onWarn, defaulting to console.warn), mirroring onError. The infinite-update-loop guard's recoverable warning now routes through it (wired end-to-end in #8658), so embedders that bridge reporting to their own telemetry no longer lose this signal to each user's browser console.
An additive extension of the $config() protocol: abstract base classes can declare configuration shared with their subclasses under a Symbol.for(<ClassName>) key (resolved by getStaticNodeConfig), and accessor-based nominal typing lets subclasses opt into stricter $config() checks. No existing node class is changed.
Any update tagged PASTE_TAG or CUT_TAG is now classified as an OTHER change inside @lexical/history, which keeps it from merging into the preceding keystrokes and keeps following keystrokes from merging into it. Undoing a short paste (or an iOS autocorrect/prediction) or a cut no longer also undoes the text you typed immediately before it.
Overrides SELECT_ALL_COMMAND so the first invocation selects the nearest block element and the second selects the entire document; a selection already spanning multiple blocks expands straight to the document, and select-all is a no-op when everything is already selected. Includes an opt-in cascadeSelection option for nested editors (image captions, etc.) and enables PreventSelectAllExtension by default to keep keydown from leaking out of input/textarea elements. (Also introduced editor.read('pending', …) via the now-generalized #8702.)
Remote collaborators' selections are now painted with the widely-supported CSS Custom Highlight API; the error-prone absolutely-positioned overlay remains only as a fallback. The remote caret is still rendered as a positioned element. Closes #4457, #5837.
A new exported helper that drops zero-area rects and any rect that contains another (with 1px tolerance) from Range.getClientRects(), fixing the duplicate/over-bright and spurious extra-wide fake-selection rects WebKit produces on some blocks. It is wired into positionNodeOnRange, so every fake-selection consumer (markSelection, selectionAlwaysOnDisplay, the extension) gets clean rects. Addresses #7106, #7492.
CodeIndentExtension gains an escapeWithArrows option (default false): when a code block is the terminal node and the caret is at the end of its text, pressing the arrow keys creates a new paragraph and moves the caret into it. New $onEscapeDown / $onEscapeUp helpers back it in @lexical/utils. Closes #7912, #4685, #5968.
LexicalErrorBoundary no longer wraps react-error-boundary (the dependency is dropped) and gains an optional fallback prop — omit it for the default message, or pass fallback={null} to render nothing. Its public type is unchanged, so it remains usable as the ErrorBoundary prop of RichTextPlugin / PlainTextPlugin.
⚠️ #8661 Deprecate unsafe type parameters on node traversal methods⚠️ #8588$getNearestNodeFromDOMNode(rootElement)resolves toRootNode; generalized captured selection viasetDOMUnmanaged({captureSelection})⚠️ #8615 Preserve the first linebreak ininsertNodes; tag managed<br>withdata-lexical-managed-linebreak- 🆕 #8694 DOM shadow root support via platform selection APIs
- 🆕 #8702
editor.read(mode, fn)overload +EditorReadMode(replacesreadPending) - 🆕 #8644
onWarneditor hook (#8658 routes the recursion guard through it end-to-end) - 🆕 #8645
$config()accessor-based nominal typing - ✅ #8598
TabNode.setTextContentfor Safari IME composition - ✅ #8604 Caret stuck when a block has no leading or trailing text
- ✅ #8680 Emit
COMPOSITION_END_TAGfrom the FirefoxonInputdefer branch - ✅ #8701 Recheck text-node contents on deletion with composition
- ✅ #8686 Reuse the empty trailing block when typing at root + last-offset selection
- ✅ #8708 Insert nodes at the block cursor inside a shadow root
- ✅ #8715 Normalize non-inline nodes when inserting into inline-only parents
- ✅ #8740 Ignore
beforeinput/inputin captured decorators (Firefox 152) - ✅ #8635 #8631 #8612 #8638 Stop the infinite-update-loop detector over-firing on fast typing; report via
devInvariant - ✅ #8617
$assumeEditorwarns viadevInvariantinstead of throwing in prod - ✅ #8726 Guard the
klass.prototypenull check ingetStaticNodeConfig - ✅ #8739 Use an
inheritsLoose-safe helper for class-inheritance loops - ✅ #8593 Harden against ReDoS and prototype pollution (linear-time regexes, prototype guards); faster CSS parsing
- 🧹 #8628 Surface a clear error when TypeScript (<5.2) can't read the package exports
- 🧹 #8579 Consolidate tokenization through
tokenizeRawText/$generateNodesFromRawText - 🧹 #8735 Better error messages for invalid node classes; cache
getStaticNodeConfig - 🧹 #8675 #8742 #8667
T[]overArray<T>, modernized Flow stubs, dropped deprecated traversal type params in tests
⚠️ 🆕 #8603 Named slots — a host node owns multiple isolated editable regions inside its owneditorState- ✅ #8716 Named-slot typing / Backspace / Copy / hydrate paths
⚠️ #8662 Register DOMImportExtension rules implicitly via node extensions; make tree-shaking annotations effective- 🧹 #8590 Migrate the playground's HTML import/export to the DOMImportExtension pipeline
- ✅ #8589
$generateHtmlFromNodesself-establishes active-editor scope (back-compat for #8519)
- 🆕 #8532
SelectBlockExtension - 🆕 #8649 Snapshot history before cut/paste so an undo doesn't swallow prior typing
- 🆕 #8393
escapeWithArrows: create a paragraph around a terminal code block with the arrow keys - 🆕 #8600 Add Go to the code-language options
- ✅ #8606 Set the unsupported-syntax flag only once (shiki)
- ✅ #8513 Skip link wrapping on paste for non-simple text nodes
- ✅ #8705 Preserve the
LinkNodewrap on copy in Firefox/Safari - ✅ #8676 Preserve a previous
DecoratorNodeon Backspace at the start of a top-level list
- ✅ #8688 Code spans bind tighter than text-match transformers
- ✅ #8723 Inline code spans containing backticks
- ✅ #8728 Preserve inline formatting when wrapping already-formatted text with matching markers
- ✅ #8678 Update the ordered-list start when typing a marker before it
- ✅ #8562 Preserve block equation markdown
- 🧹 #8717 Widen
MarkNodemethod return types toboolean(restores subclass overrides) - ✅ #8706 Correct clipboard type-checking
- ✅ #8674 Don't throw on stale table node keys in
$handleTableSelectionChangeCommand
- 🆕 #8550 Render collab cursors via the CSS Custom Highlight API
- ✅ #8611 Local range selection no longer grows when a collaborator edits
- ✅ #8652 Keep the collab cursor at element end when decoding an out-of-range position
- ✅ #8651 #6614 Avoid empty-paragraph echo and a splice crash on collab undo; don't preserve tags on non-dirty updates
- ✅ #8646 Fix Yjs desync after clearing all nodes
- ✅ #8665
@lexical/dragon: handlemakeChangesmessages and the listener-registration race
- 🆕 #8709
dedupeSelectionRects— clean up WebKit fake-selection rects - 🧹 #8733 Move
getScrollParentto@lexical/utils - ✅ #8684 Fix double paragraph creation when exiting a nested code block
- 🧹 #8720 Self-contained
LexicalErrorBoundary(dropsreact-error-boundary) with an optionalfallbackprop - 🧹 #8682 Hook syntax in
.js.flowfiles; 📝 #8714 API doc coverage of@lexical/reactexports
- ✅ #8725 Refresh the iOS keyboard suggestion bar after Backspace for all locales
- ✅ #8663 Call
preventDefault()indragoverfor HTML5 DnD compliance
- 🆕 #8574 Korean IME autocomplete with composition-idle ghost text (pluggable
AutocompleteDictionary) - 🆕 #8594 Non-printing marks (
¶,↵,→,·), toggled from Settings - ✅ #8599 Autocomplete wordlist returns the highest-priority completion
- ✅ #8666 Clear block alignment/indent on a collapsed (but not partial) selection
- ✅ #8719 Render
PageBreakNodeas<hr>so Safari firesbeforeinputafter paste - ✅ #8655 Fix the importmap of the
/esm/proof of concept - ✅ #8695 Correct the CodeBlock layout-exit e2e expected HTML
- 🧹 #8585 #8595 #8637 Audit and de-flake the e2e suite (remove all
@flakytags) - 🧹 #8639 Remove the localhost:1235 validation-server code from
ActionsPlugin
- 🧹 #8587 #8597 #8747 Consolidate release workflows and adopt npm trusted publishing
- 🧹 #8614 Vitest browser-mode tests via the Playwright runner
- 🧹 #8673 Fix intermittent
EACCESin Windows CI browser tests - 🧹 #8703 Migrate
editor.getEditorState().read(...)toeditor.read('latest', ...) - 🧹 #8634 Require all changes to be backwards compatible (
AGENTS.md/CLAUDE.md) - 🧹 #8693 Remove the unused
tmpdependency; #8647 replace thenode-state-styleexample with the dev-examples version - 🧹 Dependency bumps: #8566 #8573 #8618 #8619 #8621 #8622 #8624 #8625 #8626 #8629 #8630 #8632 #8633
- v0.45.0 by @etrepum in https://github.com/facebook/lexical/pull/8580
- build(deps-dev): bump tmp from 0.2.5 to 0.2.6 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8573
- [lexical-playground] Chore: Audit and de-flake the e2e suite (remove all @flaky tags) by @etrepum in https://github.com/facebook/lexical/pull/8585
- [lexical][lexical-code-core][lexical-code-prism][lexical-code-shiki] Chore: Consolidate text tokenization through tokenizeRawText / $generateNodesFromRawText by @etrepum in https://github.com/facebook/lexical/pull/8579
- fix(lexical-html): $generateHtmlFromNodes should self-establish active-editor scope (back-compat for #8519) by @potatowagon in https://github.com/facebook/lexical/pull/8589
- [lexical-link] Bug Fix: Skip link wrapping on paste for non-simple text nodes by @abhishekvishwakarma007 in https://github.com/facebook/lexical/pull/8513
- [lexical-playground][lexical-html][lexical-extension] Refactor: Migrate playground HTML import/export to the DOMImportExtension pipeline by @etrepum in https://github.com/facebook/lexical/pull/8590
- [Breaking Change][lexical] Feature: Generalize captured selection via setDOMUnmanaged({captureSelection}) + root _lexicalKey* stash by @mayrang in https://github.com/facebook/lexical/pull/8588
- [ci] Refactor: Consolidate release workflows + npm trusted publishing by @etrepum in https://github.com/facebook/lexical/pull/8587
- [lexical][lexical-extension][lexical-markdown][lexical-playground][lexical-yjs] Bug Fix: Linear-time regexes, prototype-pollution guards, and faster CSS parsing by @etrepum in https://github.com/facebook/lexical/pull/8593
- [lexical] Bug Fix: TabNode.setTextContent for Safari IME composition by @mayrang in https://github.com/facebook/lexical/pull/8598
- [lexical-playground] Feature: Korean IME autocomplete with composition-idle ghost by @mayrang in https://github.com/facebook/lexical/pull/8574
- [ci] Bug Fix: Trusted-publishing follow-ups (TTY-aware setup script, unify nightly, drop NPM_TOKEN) by @etrepum in https://github.com/facebook/lexical/pull/8597
- [lexical-playground] Bug Fix: AutocompleteExtension wordlist returns the highest-priority completion by @etrepum in https://github.com/facebook/lexical/pull/8599
- [lexical-playground][lexical-website] Feature: Non-printing marks (#8592) by @mayrang in https://github.com/facebook/lexical/pull/8594
- [lexical-playground] Chore: De-flake e2e timing- and history-dependent tests by @etrepum in https://github.com/facebook/lexical/pull/8595
- [lexical-code-shiki] Bug Fix: Set the unsupported syntax flag only once by @levensta in https://github.com/facebook/lexical/pull/8606
- [lexical-code-prism][lexical-playground] Feature: Add Go to code language options by @meaqua9420 in https://github.com/facebook/lexical/pull/8600
- [lexical-rich-text] Bug Fix: Caret stuck when block has no leading or trailing text by @mayrang in https://github.com/facebook/lexical/pull/8604
- Include editor namespace in infinite-update-loop detector error by @potatowagon in https://github.com/facebook/lexical/pull/8612
- [lexical-extension][lexical-react][lexical-playground] Chore: Add Vitest browser-mode tests via the Playwright runner by @etrepum in https://github.com/facebook/lexical/pull/8614
- fix(lexical): reconcile DOM mutations targeting the root element by @potatowagon in https://github.com/facebook/lexical/pull/8613
- revert(lexical): remove root-element carveout from #8613 (keep the typing test) by @potatowagon in https://github.com/facebook/lexical/pull/8616
- [lexical-yjs] Bug Fix: Local range selection grows when collaborator … by @sahiee-dev in https://github.com/facebook/lexical/pull/8611
- [lexical] Refactor: $assumeEditor now uses devInvariant instead of invariant to warn instead of throwing in prod by @etrepum in https://github.com/facebook/lexical/pull/8617
- build(deps): bump the docusaurus-and-typedoc group with 2 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8618
- build(deps): bump @rollup/rollup-linux-x64-gnu from 4.52.0 to 4.61.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8621
- build(deps-dev): bump the flow-and-hermes group with 5 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8619
- build(deps): bump @shikijs/engine-javascript from 4.0.2 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8622
- build(deps): bump yjs from 13.6.30 to 13.6.31 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8624
- build(deps): bump @shikijs/langs from 3.23.0 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8626
- build(deps): bump lucide-react from 0.503.0 to 1.17.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8625
- build(deps): bump @huggingface/transformers from 4.0.1 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8629
- build(deps-dev): bump the dev-dependencies group across 1 directory with 29 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8630
- build(deps): bump webpack-dev-server to >=5.2.4 (CVE-2026-6402) by @xiezhenjia-meta in https://github.com/facebook/lexical/pull/8632
- build(deps): bump vitest to ^4.1.8 in examples (CVE-2026-47429) by @xiezhenjia-meta in https://github.com/facebook/lexical/pull/8633
- fix: bump astro to ^6.1.10 to resolve CVE-2026-45028 by @freddymeta in https://github.com/facebook/lexical/pull/8566
- [lexical] Bug Fix: use devInvariant for update recursion guard to avoid reporting a recovered condition as an uncaught error by @potatowagon in https://github.com/facebook/lexical/pull/8631
- [*] Bug Fix: Surface a clear error when TypeScript (<5.2) can't read the package exports by @etrepum in https://github.com/facebook/lexical/pull/8628
- [lexical-playground] Chore: De-flake collab "Undo with collaboration on" e2e test by @etrepum in https://github.com/facebook/lexical/pull/8637
- [lexical] Chore: cover both devInvariant branches in update-recursion guard test by @potatowagon in https://github.com/facebook/lexical/pull/8638
- [lexical-playground] Chore: Remove localhost:1235 validation server code from ActionsPlugin by @etrepum in https://github.com/facebook/lexical/pull/8639
- [*] Chore: require all changes to be backwards compatible by @potatowagon in https://github.com/facebook/lexical/pull/8634
- [lexical-code-core][lexical-playground] Feature: Create paragraph around the code node when navigating with the arrow keys by @levensta in https://github.com/facebook/lexical/pull/8393
- [lexical] Extend the $config() protocol with accessor-based nominal typing by @etrepum in https://github.com/facebook/lexical/pull/8645
- [lexical-yjs][lexical-react] Feature: Render collab cursors via CSS custom Highlight API by @hamza512b in https://github.com/facebook/lexical/pull/8550
- [examples] Chore: Replace node-state-style with the dev-examples version by @etrepum in https://github.com/facebook/lexical/pull/8647
- [lexical][lexical-history][lexical-rich-text][lexical-plain-text] Feature: Snapshot history before cut/paste operations by @etrepum in https://github.com/facebook/lexical/pull/8649
- [lexical] Feature: add an onWarn editor hook and route the update-recursion guard through it by @potatowagon in https://github.com/facebook/lexical/pull/8644
- [lexical-playground] Bug Fix: Fix the importmap of the /esm/ proof of concept by @etrepum in https://github.com/facebook/lexical/pull/8655
- [lexical-yjs] Bug Fix: keep collab cursor at element end when decoding an out-of-range position by @ivanscm in https://github.com/facebook/lexical/pull/8652
- [lexical][lexical-react] Bug Fix: actually route the update-recursion guard through editor._onWarn end-to-end (follow-up to #8644) by @potatowagon in https://github.com/facebook/lexical/pull/8658
- [lexical][lexical-yjs] Bug Fix: avoid empty-paragraph echo and splice crash on collab undo (#6614) and don't preserve tags on non-dirty update by @ivanscm in https://github.com/facebook/lexical/pull/8651
- [lexical-yjs] Bug Fix: Yjs desynchronizes after clearing all nodes by @sahiee-dev in https://github.com/facebook/lexical/pull/8646
- [Breaking Change][lexical][*] Chore: deprecate unsafe type parameters on node traversal methods by @etrepum in https://github.com/facebook/lexical/pull/8661
- [Breaking Changes][*] Refactor: Register DOMImportExtension rules implicitly via node extensions and make tree-shaking annotations effective by @etrepum in https://github.com/facebook/lexical/pull/8662
- [lexical][*] Chore: stop using deprecated traversal type parameters in tests by @etrepum in https://github.com/facebook/lexical/pull/8667
- [lexical] Bug Fix: stop infinite-update-loop detector over-firing on bounded activity (fast typing) by @potatowagon in https://github.com/facebook/lexical/pull/8635
- [lexical-dragon] Bug Fix: Handle makeChanges messages and the listener registration race by @brunoprietog in https://github.com/facebook/lexical/pull/8665
- [lexical][lexical-utils][lexical-extension][lexical-playground] Feature: SelectBlockExtension by @levensta in https://github.com/facebook/lexical/pull/8532
- [ci] Bug Fix: Fix intermittent EACCES in Windows CI browser tests by pinning Vitest browser port by @etrepum in https://github.com/facebook/lexical/pull/8673
- [lexical-table] Bug Fix: don't throw on stale table node keys in $handleTableSelectionChangeCommand by @etrepum in https://github.com/facebook/lexical/pull/8674
- [*] Chore: always use T[] syntax instead of Array in TypeScript and Flow by @etrepum in https://github.com/facebook/lexical/pull/8675
- [lexical] Bug Fix: Emit COMPOSITION_END_TAG from the Firefox onInput defer branch by @mayrang in https://github.com/facebook/lexical/pull/8680
- [lexical-markdown] Bug Fix: Update ordered list start when typing a marker before it by @mayrang in https://github.com/facebook/lexical/pull/8678
- [lexical-list] Bug Fix: Preserve previous DecoratorNode on Backspace at the start of a top-level list by @mayrang in https://github.com/facebook/lexical/pull/8676
- [lexical-playground] Bug Fix: clear block alignment and indent with a collapsed selection but not a partial one by @achaljhawar in https://github.com/facebook/lexical/pull/8666
- [lexical-react] Refactor: Use hook syntax in .js.flow files to better declare intent by @SamChou19815 in https://github.com/facebook/lexical/pull/8682
- [lexical-rich-text][lexical-plain-text] Spec hardening: call event.preventDefault() in dragover for HTML5 DnD compliance by @sahiee-dev in https://github.com/facebook/lexical/pull/8663
- [lexical-utils][lexical-playground] Bug Fix: Double paragraph creation when exiting a nested code block by @levensta in https://github.com/facebook/lexical/pull/8684
- [lexical-markdown] Bug Fix: code spans should bind tighter than text-match transformers by @etrepum in https://github.com/facebook/lexical/pull/8688
- [lexical] Bug Fix: Reuse the empty trailing block when typing at root + last-offset selection by @mayrang in https://github.com/facebook/lexical/pull/8686
- [lexical] Chore: Remove unused tmp dependency by @noritaka1166 in https://github.com/facebook/lexical/pull/8693
- [Breaking Change][lexical] Fix: Preserve the first linebreak when passing inline nodes to insertNodes and add data-lexical-managed-linebreak attribute to managed linebreaks by @levensta in https://github.com/facebook/lexical/pull/8615
- [lexical-playground] Bug Fix: CodeBlock layout-exit e2e expected HTML by @mayrang in https://github.com/facebook/lexical/pull/8695
- [lexical] Feature: Replace LexicalEditor.readPending with editor.read(mode, fn) overload by @etrepum in https://github.com/facebook/lexical/pull/8702
- [lexical] Bug Fix: Recheck text node contents on deletion with composition by @ewsbr in https://github.com/facebook/lexical/pull/8701
- [lexical-playground] Bug Fix: Preserve block equation markdown by @vivekjm in https://github.com/facebook/lexical/pull/8562
- [Breaking Changes][lexical][lexical-yjs][lexical-clipboard][lexical-html][lexical-playground] Feature: Named slots by @mayrang in https://github.com/facebook/lexical/pull/8603
- [lexical-clipboard] Bug Fix: Correct type-checking by @levensta in https://github.com/facebook/lexical/pull/8706
- [Breaking Changes][lexical-link][lexical-list][lexical-react] Chore: Remove a subset of v0.32.1-deprecated exports by @etrepum in https://github.com/facebook/lexical/pull/8704
- [lexical-link] Bug Fix: Preserve LinkNode wrap on copy in Firefox/Safari by @mayrang in https://github.com/facebook/lexical/pull/8705
- [lexical] Bug Fix: Insert nodes at the block cursor inside a shadow root by @etrepum in https://github.com/facebook/lexical/pull/8708
- [lexical-react][lexical-link][lexical-history][lexical-extension] Docs: API doc coverage of react exports by @etrepum in https://github.com/facebook/lexical/pull/8714
- [lexical-react][lexical-playground] Refactor: Replace react-error-boundary with a self-contained LexicalErrorBoundary by @etrepum in https://github.com/facebook/lexical/pull/8720
- [*] Refactor: Migrate editor.getEditorState().read(...) to editor.read('latest', ...) by @etrepum in https://github.com/facebook/lexical/pull/8703
- [lexical-playground] Bug Fix: Render PageBreakNode as
so Safari fires beforeinput after paste by @mayrang in https://github.com/facebook/lexical/pull/8719 - [lexical-mark] Chore: Widen MarkNode method return types to boolean by @patrick-atticus in https://github.com/facebook/lexical/pull/8717
- [lexical][lexical-rich-text][lexical-clipboard] Bug Fix: Named-slot typing / Backspace / Copy / hydrate paths by @mayrang in https://github.com/facebook/lexical/pull/8716
- [lexical-markdown] Bug Fix: Inline code spans containing backticks by @baptistejamin in https://github.com/facebook/lexical/pull/8723
- [lexical-plain-text][lexical-rich-text] Bug Fix: Refresh iOS keyboard suggestion bar after Backspace for all locales by @levensta in https://github.com/facebook/lexical/pull/8725
- fix(lexical): guard klass.prototype null check in getStaticNodeConfig by @potatowagon in https://github.com/facebook/lexical/pull/8726
- [lexical-markdown] Bug Fix: Preserve inline formatting when wrapping already-formatted text with matching markers by @koki-develop in https://github.com/facebook/lexical/pull/8728
- [lexical-utils] Add dedupeSelectionRects: fix duplicate/extra selection rects on WebKit (#7106, #7492) by @pro-vi in https://github.com/facebook/lexical/pull/8709
- [lexical] Bug Fix: Normalize non-inline nodes when inserting into inline-only parents by @etrepum in https://github.com/facebook/lexical/pull/8715
- [lexical] Feature: Support DOM shadow roots via platform selection APIs by @mayrang in https://github.com/facebook/lexical/pull/8694
- [lexical-utils][lexical-react] Chore: Move getScrollParent to @lexical/utils by @mayrang in https://github.com/facebook/lexical/pull/8733
- [lexical] Refactor: Improve error messages for invalid node classes and cache getStaticNodeConfig by @etrepum in https://github.com/facebook/lexical/pull/8735
- [lexical] Bug Fix: Refactor class inheritance loops to use an inheritsLoose-safe helper by @etrepum in https://github.com/facebook/lexical/pull/8739
- [lexical] Modernize Flow type-stub syntax rejected by fb-www flow strict by @potatowagon in https://github.com/facebook/lexical/pull/8742
- [lexical] Bug Fix: Ignore beforeinput and input events in captured decorators by @etrepum in https://github.com/facebook/lexical/pull/8740
- [ci] Bug Fix: grant id-token: write in version.yml release call by @etrepum in https://github.com/facebook/lexical/pull/8747
- @meaqua9420 made their first contribution in https://github.com/facebook/lexical/pull/8600
- @sahiee-dev made their first contribution in https://github.com/facebook/lexical/pull/8611
- @xiezhenjia-meta made their first contribution in https://github.com/facebook/lexical/pull/8632
- @freddymeta made their first contribution in https://github.com/facebook/lexical/pull/8566
- @hamza512b made their first contribution in https://github.com/facebook/lexical/pull/8550
- @ivanscm made their first contribution in https://github.com/facebook/lexical/pull/8652
- @brunoprietog made their first contribution in https://github.com/facebook/lexical/pull/8665
- @ewsbr made their first contribution in https://github.com/facebook/lexical/pull/8701
- @vivekjm made their first contribution in https://github.com/facebook/lexical/pull/8562
- @koki-develop made their first contribution in https://github.com/facebook/lexical/pull/8728
Full Changelog: https://github.com/facebook/lexical/compare/v0.45.0...v0.46.0
v0.45.0
v0.45.0 is a monthly release with several breaking changes around selection and reconcile semantics, a major new experimental DOMImportExtension API for composable HTML import that replaces importDOM, a generalized DOMSlot and DOM render override surface, new HistoryExtension ergonomics (canUndo/canRedo signals, maxDepth), notable reconciler/selection performance work, and a wide range of bug fixes across IME, mobile keyboards, list/code/table editing, and markdown round-tripping.
$getReconciledDirection now walks through shadow roots when resolving the reconciled dir attribute on a node, so nested ShadowRoot-style elements (e.g. tables) inherit direction consistently with regular elements. Callers that relied on direction inheritance stopping at shadow roots will need to update.
Pressing Backspace at the start of a non-empty block previously merged the current block into the previous block, which discarded the current block's type/format. The new behavior merges the previous block's children into the current block instead, preserving the current block's type (heading, list item, quote, etc.). A new $mergeBlockBackward helper on RangeSelection is exposed for custom command handlers that want the same behavior.
LexicalNode.replace, insertBefore, insertAfter, and related callers that move a node between parents now correctly adjust the current selection to follow the moved node instead of leaving the selection pointing at the (now empty) original slot. This may change selection state observed by transforms or update listeners that previously relied on the stale offsets.
Markdown shortcuts (e.g. *, _, ~) typed via IME composition now trigger after the composition is committed, not just on raw beforeinput. This fixes shortcuts being silently dropped during Japanese / Korean / Chinese input but may also fire shortcuts in some flows that previously didn't.
@lexical/extension / @lexical/rich-text / @lexical/plain-text — NormalizeInlineElementsExtension (#8497)
registerRichText and registerPlainText now register a transform that removes empty inline elements (e.g. LinkNode, formatted TextNode wrappers with no children) instead of leaving them in the tree. The transform is also exported as NormalizeInlineElementsExtension from @lexical/extension for use with extension-based setups. Editors that intentionally kept empty inline wrappers will need to disable the extension or override the transform. See Included Extensions.
lexical / @lexical/extension / @lexical/rich-text / @lexical/plain-text — NormalizeTripleClickSelectionExtension (#8520)
The "triple-click selects the whole paragraph including the trailing newline" normalization has moved out of LexicalEvents and into a new NormalizeTripleClickSelectionExtension registered by both rich-text and plain-text. The core LexicalEditor no longer performs this normalization on its own, so editors that bypass registerRichText / registerPlainText (or the equivalent extensions) need to register the extension explicitly to keep the previous behavior. See Included Extensions.
lexical / @lexical/html / @lexical/selection / @lexical/utils / @lexical/playground — Generalized DOMSlot and DOMRenderExtension override surface (#8519)
DOMSlot is now generalized so child slots can be expressed for arbitrary DOM containers (not just the direct child element), and $createDOM, $updateDOM, $exportDOM, $getDOMSlot etc. all flow through the new override surface. The previously-exported AutocompleteNode in the playground has been replaced by a VisibleLineBreakExtension that demonstrates the new override surface, and markSelection in @lexical/utils has been rewritten on top of the generalized slot API. Custom nodes that override getDOMSlot to return a non-element wrapper now have a real way to express that. See the DOMRenderExtension docs.
A new DOMImportExtension replaces the legacy node-class importDOM static method with a composable middleware-style API. Rules declare a CSS-selector-style matcher, an optional schema for child handling, and a DOMImportFn that builds Lexical nodes from the matching DOM. Many helpers ship alongside it: $distributeInlineWrapper, ImportSession, DOMPreprocessFn for source-specific cleanup (Word, VS Code, etc.), and full TypeScript types for rules, captures, and contexts. A new dev-examples/dom-import showcase wires it up to a Word/VS Code paste flow. The legacy importDOM continues to work; new code can opt in to DOMImportExtension for richer composition and explicit ordering. The companion ClipboardDOMImportExtension (in @lexical/clipboard) routes text/html pastes through the new pipeline. See the DOMImportExtension guide and the "Migrating from importDOM" section.
domOverride now supports disabledForEditor and disabledForSession predicates so render overrides can be conditionally skipped on a per-editor or per-session basis (e.g. only apply during export, or only when a feature flag is on). Useful when one extension provides multiple overrides whose applicability depends on context that isn't known at registration time. See the DOMRenderExtension docs.
ElementNode now uniformly imports and exports the data-lexical-indent attribute so any subclass round-trips its indent level through HTML without having to override exportDOM / importDOM (fixes the long-standing #7729 regression around indented headings/paragraphs).
Update listeners and update transforms that re-trigger themselves are now caught by a runtime guard that throws a descriptive error after a configurable number of nested updates, instead of hanging the tab. See Updates and Listeners.
HistoryExtension's output now exposes canUndo and canRedo as ReadonlySignal<boolean>s so toolbar buttons can subscribe directly without polling historyState or duplicating the priority/state bookkeeping. See Extension Signals.
HistoryExtension accepts a new maxDepth option that bounds the undo stack. Older entries are evicted FIFO when the depth is exceeded. See the new "Tuning HistoryExtension for memory and long sessions" docs.
Counterpart to $convertToMarkdownString that serializes only the current selection (or any caller-provided range) to a markdown string, useful for "copy as markdown" toolbar actions and for selection-scoped AI prompts.
A new $setFormatFromDOM helper extracts text-align / dir from a DOM element and applies it to an ElementNode. ListItemNode.importDOM now uses it to correctly import alignment for list items pasted from external sources.
ListNode exposes a createListItemNode factory that is now used by children-normalization, so ListNode subclasses can supply a custom ListItemNode subclass without monkey-patching the normalizer.
RichTextExtension now accepts an escapeFormatTriggers config (a ReadonlySignal<EscapeFormatTriggerConfig>) that opts text-format escape behavior in/out per trigger (enter, click, arrow, space, tab). With it enabled, typing at the boundary of a formatted text node "escapes" the active format (bold, italic, code, etc.), matching the typing experience in Google Docs / Notion. Disabled by default. See Included Extensions.
New ClickAfterLastBlockExtension inserts a fresh paragraph when the user clicks below the last block (and places the caret in it), so single-block editors and short documents don't strand the user with no easy way to start a new line.
Tokenizer.defaultLanguage may now be null to indicate that code blocks without an explicit language should round-trip through markdown without injecting a default language tag (e.g. ```javascript). Preserves CommonMark's "no fence info" form on export.
@lexical/code-core / @lexical/code-shiki / @lexical/code-prism — Outdent space-indented code lines (#8445)
Shift+Tab in a code block now correctly outdents space-indented lines (not just tab-indented), respecting the tokenizer's configured indent width.
LexicalTypeaheadMenuPlugin's onClose may now return a Promise, useful for handlers that need to await network or animation work before tearing down the menu.
GetClipboardDataExtension is now exported from @lexical/clipboard for use as a peer dependency from custom clipboard handlers.
Every docs page now has a server-rendered "Copy page as Markdown" button (and a matching ?raw URL) so AI assistants and humans can grab the raw markdown without scraping the rendered HTML.
Core:
⚠️ #8479 Include shadow root in$getReconciledDirection⚠️ #8493 Backspace at block start now preserves the current block (heading / list item / quote)⚠️ #8501 Adjust selection whenLexicalNodecallers move a node out of its parent⚠️ #8519 GeneralizeDOMSlotand add DOMRenderExtension override surface;markSelectionrewritten on top⚠️ #8520 Move triple-click selection normalization toNormalizeTripleClickSelectionExtension- 🆕 #8536
ElementNodeimport/export ofdata-lexical-indent - 🆕 #8542 Detect infinite recursion in update listeners and transforms
- ⚡ #8422 Defer DOM Selection property reads in
$updateDOMSelection - ⚡ #8474 Cache
RangeSelection.isBackward()on the instance - ⚡ #8481 Adopt GenMap copy-on-write for
NodeMapand reconcilerkeyToDOMMap - ⚡ #8482 Children fast path with suffix-incremental cache update in
$reconcileChildren - ⚡ #8505 Centralize replace-area selection mapping + bulk splice across list/selection/link
- ⚡ #8548 Cache last-child kind for trailing-
<br>reconcile - ✅ #8412 Import
dirattribute inimportDOM - ✅ #8417 Workarounds for buggy browser behavior around macOS text replacements
- ✅ #8428 Respect CSS
displaystyle inisBlockDomNode/isInlineDomNode - ✅ #8441 Reuse DOM when reconciling cross-parent node moves
- ✅ #8466 Resolve
--lexical-indent-base-valuevia CSSvar()instead of pre-computing in JS - ✅ #8470 Preserve queued updates and tags through
setRootElement - ✅ #8475 Handle iOS 10-key Korean IME
deleteContentBackwardwithtargetRange - ✅ #8486 Keep caret above the on-screen keyboard after Enter
- ✅ #8517 Handle triple-click overselection in
$setBlocksType - ✅ #8547 Migrate away from legacy Flow syntax in flow definitions
- ✅ #8558 Cursor stuck before leading inline
DecoratorNode - ✅ #8564 Skip
$reconcileChildrenfast path during full reconcile - ✅ #8569 Correct children fast-path text size for cross-parent-moved elements
- ✅ #8577 Prevent
MOVE_TO_END/MOVE_TO_STARTcrash on decorator-only elements - ✅ #8581 Restore Shift+Cmd+Arrow selection expansion for
MOVE_TO_END/MOVE_TO_START
HTML / DOM:
- 🆕 #8528
DOMImportExtension— composable replacement forimportDOMwith rule-based matchers and DOM preprocessing - 🆕 #8575
disabledForEditor/disabledForSessionpredicates ondomOverride
Code:
- 🆕 #8445 Outdent space-indented code lines on Shift+Tab
- 🆕 #8553 Allow
nullTokenizer.defaultLanguageto preserve markdown ``` round-trip - ✅ #8487 Detect nested
<br>elements in pasted code - ✅ #8514 Externalize shiki dependencies in the published bundle
Clipboard:
- 🧹 #8431 Export
GetClipboardDataExtension
Extension:
- 🆕 #8497
NormalizeInlineElementsExtension(also wired into rich/plain text) - 🆕 #8520
NormalizeTripleClickSelectionExtension - 🆕 #8549
ClickAfterLastBlockExtension - ✅ #8510 Set the correct default
$canIndent
History:
- 🆕 #8465
canUndo/canRedoReadonlySignals onHistoryExtension - 🆕 #8537
maxDepthoption for bounding the undo stack
Link / List:
- 🆕 #8460
$setFormatFromDOM;ListItemNodeimports alignment from DOM - 🆕 #8427
ListNode.createListItemNodefactory for subclasses
Markdown:
⚠️ #8503 Apply markdown shortcuts on composition-committed triggers (fixes IME-typed*/_/~)- 🆕 #8395
$convertSelectionToMarkdownStringAPI - ✅ #8402 Preserve hard line breaks in default markdown import
- ✅ #8488 Run element-shortcut transforms on Enter
- ✅ #8535 Fix markdown import with Unicode whitespace
React:
- 🆕 #8489 Optional async
onCloseforLexicalTypeaheadMenuPlugin - ✅ #8411 Pass editor context to
editorState.read()inmarkSelection - ✅ #8472
ExtensionComponentsupport for output components with required props - 🧹 #8485 Make
onOpenEmbedModalForConfigprop optional inLexicalAutoEmbedPlugin
Rich Text / Plain Text:
- 🆕 #8383 Opt-in
escapeFormatTriggersonRichTextExtension - ✅ #8526 Insert paragraph on Enter for a block
DecoratorNodeNodeSelection
Table:
- ✅ #8492 Attach window
pointerdownhandler when root element is set after register - ✅ #8502 Prevent crash when moving selection with arrow key outside of nested table
Yjs:
- ✅ #8461 Handle node state being removed on non-
TextNodes in collab v2 - 🧹 #8527 Fix
RenderSnapshotcomment typo
Playground:
- 🆕 #8464 New "markdown-editor split-view" example
- ✅ #8419 #8432 Position
FloatingLinkEditorcorrectly for multi-line / decorator-only links and near the editor's bottom edge - ✅ #8442 Prevent crash importing
<details>with loose body content - ✅ #8444 Allow
PagesExtensionto be disabled byActionsPlugin(HTML & markdown mode) - ✅ #8453 Convert selection to a code block in place
- ✅ #8480 Prevent auto-zoom when focusing in the editor on iOS Safari
- ✅ #8496 Set
font-sizeforh2 - ✅ #8521 Fix unawaited Playwright promises in e2e suite
- ✅ #8534
EquationNodeclick →NodeSelection; empty-input Backspace removes - ✅ #8539 Normalize collapsible content children
- ✅ #8565 Build dev playground in development mode
Website / Examples:
- 🆕 #8570 Server-rendered "Copy page as Markdown" button
- 🆕 #8546 "Tuning HistoryExtension for memory and long sessions" docs
- 🆕 #8429 Clarify
editorStatenullvsundefinedand empty-state pitfall - 🆕 #8467 Document
NodeStatein$configJSON serialization - 🆕 #8471 TSDoc for
LexicalNodeReplacementandwithKlass - 🆕 #8476 Add missing
@lexical/reactplugin docs - 🧹 #8430 Inline toolbar SVG icons in examples via Vite asset handling
- 🧹 #8403 Merge
dev-node-state-styleintoexamples/node-state-style - 🧹 #8473 Disable
skipLibCheckinreact-richfor lib-types regression coverage (#7093) - ✅ #8462 Add the missing links to the sandbox
- ✅ #8463 #8483 Fix copyright statement to pass OSS automated checkup
- ✅ #8498
update-team-data - ✅ #8509 Drop Vercel Analytics inject and unwrap chat input from flex parent
- ✅ #8516 Drop
docusaurus-plugin-internaldocs-fbpreset - ✅ #8523 Correct links to included extensions
- ✅ #8531 Remove
embed=1from non-iframe StackBlitz links - ✅ #8557 Fix crash on
/docs/errorpage from undefinedprocess
Infrastructure:
- 🧹 #8554 Publish packages from their root directory
- 🧹 #8512 Respect
browserslist - 🧹 #8504 Use composite actions to simplify GitHub workflows
- 🧹 #8494 Only cancel in-progress workflows on newer commits
- 🧹 #8499 Run extended tests on new commits to approved PRs
- 🧹 #8508 Drop FIXME #8348 Firefox
ArrowDownworkaround inTables.spec.mjs - 🧹 #8522 Pin Windows e2e runners to
windows-2022 - 🧹 #8572 Use
playwright install-depsinstead ofapt-get - 🧹 #8582 Upgrade
@playwright/testto^1.60.0 - 🧹 #8541 Cover bold-italic markdown round trip
- 🧹 #8400 Fix release workflow's missing rename from
release.jstorelease.mjs - 🧹 #8401 #8404 #8405 #8406 #8408 #8409 #8415 #8540 Dependency vulnerability fixes (protobufjs, dompurify, postcss, astro, eslint, immutable, path-to-regexp, serialize-javascript)
- v0.44.0 by @etrepum in https://github.com/facebook/lexical/pull/8394
- [*] Bug Fix: Fix release workflow's missing rename from release.js to release.mjs by @etrepum in https://github.com/facebook/lexical/pull/8400
- [lexical] Chore: Fix protobufjs dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8401
- [lexical] Chore: Fix dompurify dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8404
- [lexical] Chore: Fix postcss dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8405
- [lexical] Chore: Fix astro dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8406
- [examples] Chore: Merge dev-node-state-style into examples/node-state-style by @etrepum in https://github.com/facebook/lexical/pull/8403
- [lexical] Chore: Fix eslint dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8408
- [lexical] Chore: Fix immutable dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8409
- [lexical][lexical-rich-text][lexical-list] Bug Fix: Import dir attribute in importDOM by @mayrang in https://github.com/facebook/lexical/pull/8412
- [lexical] Chore: Fix path-to-regexp dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8415
- [lexical-utils] Bug Fix: Pass editor context to editorState.read() in markSelection by @potatowagon in https://github.com/facebook/lexical/pull/8411
- [lexical-markdown] Feature: Add $convertSelectionToMarkdownString API by @mayrang in https://github.com/facebook/lexical/pull/8395
- [lexical] perf: defer DOM Selection property reads in $updateDOMSelection by @rhagigi in https://github.com/facebook/lexical/pull/8422
- [lexical-playground] Bug Fix: Position FloatingLinkEditor below the entire link for multi-line and decorator-only links by @mayrang in https://github.com/facebook/lexical/pull/8419
- Chore: Inline toolbar SVG icons in examples via Vite asset handling by @markselby9 in https://github.com/facebook/lexical/pull/8430
- [lexical-website][lexical-react] Documentation Update: Clarify editorState null vs undefined and empty-state pitfall by @markselby9 in https://github.com/facebook/lexical/pull/8429
- [lexical] Bug Fix: Respect CSS display style in isBlockDomNode and isInlineDomNode by @abhishekvishwakarma007 in https://github.com/facebook/lexical/pull/8428
- [lexical-clipboard] Chore: Export GetClipboardDataExtension by @ibastawisi in https://github.com/facebook/lexical/pull/8431
- [lexical-playground] Bug Fix: Prevent FloatingLinkEditor toolbar from being clipped near the editor's bottom edge by @mayrang in https://github.com/facebook/lexical/pull/8432
- [lexical][lexical-playground] Bug Fix: Add workarounds for buggy browser behavior around macOS text replacements by @nmggithub in https://github.com/facebook/lexical/pull/8417
- [lexical-markdown] Bug Fix: Preserve hard line breaks in default markdown import by @pro-vi in https://github.com/facebook/lexical/pull/8402
- [lexical][lexical-list] Bug Fix: Reuse DOM when reconciling cross-parent node moves by @mayrang in https://github.com/facebook/lexical/pull/8441
- [lexical-playground] Bug Fix: Prevent crash importing
with loose body content by @markselby9 in https://github.com/facebook/lexical/pull/8442
- [lexical-playground] Bug Fix: Allow PagesExtension to be disabled by ActionsPlugin (html & markdown mode) by @etrepum in https://github.com/facebook/lexical/pull/8444
- [lexical-list] Feature: Add the
createListItemNodemethod to the ListNode and use it for children normalization by @levensta in https://github.com/facebook/lexical/pull/8427 - [lexical-rich-text] Feature: Add opt-in format escape triggers for RichTextExtension by @vishisht31 in https://github.com/facebook/lexical/pull/8383
- build(deps): bump @floating-ui/react from 0.27.16 to 0.27.19 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8448
- build(deps): bump happy-dom from 20.8.9 to 20.9.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8451
- [lexical-code-core][lexical-code-shiki][lexical-code-prism] Feature: Outdent space-indented code lines by @mayrang in https://github.com/facebook/lexical/pull/8445
- [lexical-playground] Bug Fix: Convert selection to a code block in place by @mayrang in https://github.com/facebook/lexical/pull/8453
- build(deps-dev): bump the dev-dependencies group across 1 directory with 30 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8447
- build(deps): bump yjs from 13.6.27 to 13.6.30 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8449
- build(deps-dev): bump @types/jsdom from 21.1.6 to 28.0.1 in the dev-dependencies group by @dependabot[bot] in https://github.com/facebook/lexical/pull/8455
- build(deps): bump react-day-picker from 9.12.0 to 9.14.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8458
- build(deps): bump react-error-boundary from 6.0.0 to 6.1.1 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8456
- [lexical-yjs] Bug Fix: Handle node state being removed on non-TextNodes in collab v2 by @james-atticus in https://github.com/facebook/lexical/pull/8461
- [examples] Docs: Add the missing links to the sandbox by @levensta in https://github.com/facebook/lexical/pull/8462
- [lexical][lexical-list] Feature: Add
$setFormatFromDOMfunction and use it to import alignment for ListItem by @levensta in https://github.com/facebook/lexical/pull/8460 - build(deps): bump @chakra-ui/react from 2.10.9 to 3.35.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8457
- [lexical-website] Fix copyright statement to pass OSS automated checkup by @potatowagon in https://github.com/facebook/lexical/pull/8463
- [lexical] Bug Fix: Resolve --lexical-indent-base-value via CSS var() instead of pre-computing in JS by @mayrang in https://github.com/facebook/lexical/pull/8466
- [lexical-website] Documentation Update: Document NodeState in $config JSON serialization by @markselby9 in https://github.com/facebook/lexical/pull/8467
- [lexical-website] Documentation: Add missing @lexical/react plugin docs by @abhishekvishwakarma007 in https://github.com/facebook/lexical/pull/8476
- [lexical] Refactor: Cache RangeSelection.isBackward() result on the instance by @mayrang in https://github.com/facebook/lexical/pull/8474
- [examples] Chore: Disable skipLibCheck in react-rich for lib-types regression coverage (#7093) by @markselby9 in https://github.com/facebook/lexical/pull/8473
- [lexical] Documentation: Add TSDoc for LexicalNodeReplacement and withKlass by @markselby9 in https://github.com/facebook/lexical/pull/8471
- [lexical-history] Feature: Add canUndo and canRedo ReadonlySignals to HistoryExtension output by @etrepum in https://github.com/facebook/lexical/pull/8465
- [lexical-react] Bug Fix: ExtensionComponent support for output Components with required props by @etrepum in https://github.com/facebook/lexical/pull/8472
- [lexical] Perf: Adopt GenMap copy-on-write for NodeMap and reconciler keyToDOMMap by @mayrang in https://github.com/facebook/lexical/pull/8481
- [lexical] Bug Fix: Preserve queued updates and tags through setRootElement by @mayrang in https://github.com/facebook/lexical/pull/8470
- Fix: Copyright statement to match OSS automated checkup regex by @potatowagon in https://github.com/facebook/lexical/pull/8483
- [Breaking Change][lexical] Bug Fix: Include shadow root in $getReconciledDirection by @ibastawisi in https://github.com/facebook/lexical/pull/8479
- [lexical-playground] Fix: Prevent auto-zoom when focusing in the editor in iOS Safari by @levensta in https://github.com/facebook/lexical/pull/8480
- [lexical] Bug Fix: keep caret above the on-screen keyboard after Enter by @jWA86 in https://github.com/facebook/lexical/pull/8486
- [lexical-code-core] Bug Fix: detect nested br elements in pasted code by @danyalahmed1995 in https://github.com/facebook/lexical/pull/8487
- [lexical-react] Chore: Make
onOpenEmbedModalForConfigprop optional in LexicalAutoEmbedPlugin by @levensta in https://github.com/facebook/lexical/pull/8485 - [lexical-table] Bug Fix: Attach window pointerdown handler when root element is set after register by @etrepum in https://github.com/facebook/lexical/pull/8492
- [examples][lexical-website] Feature: Add markdown-editor split-view example by @etrepum in https://github.com/facebook/lexical/pull/8464
- [ci] Bug Fix: Only cancel in-progress workflows on newer commits by @etrepum in https://github.com/facebook/lexical/pull/8494
- [Breaking Change][lexical] Bug Fix: Backspace at block start preserves the current block by @mayrang in https://github.com/facebook/lexical/pull/8493
- [lexical] Bug Fix: Handle iOS 10-key Korean IME deleteContentBackward with targetRange by @kotom320 in https://github.com/facebook/lexical/pull/8475
- [lexical-website] Chore: pnpm run update-team-data by @etrepum in https://github.com/facebook/lexical/pull/8498
- build(deps): bump mermaid from 11.14.0 to 11.15.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8500
- [ci] Bug Fix: Run extended tests on new commits to approved PRs by @etrepum in https://github.com/facebook/lexical/pull/8499
- [lexical-playground] Bug Fix: Set font-size for h2 by @levensta in https://github.com/facebook/lexical/pull/8496
- [Breaking Change][lexical] Bug Fix: Adjust selection when removeFromParent callers move a node out of its parent by @mayrang in https://github.com/facebook/lexical/pull/8501
- [lexical] Perf: Children fast path with suffix-incremental cache update in $reconcileChildren by @mayrang in https://github.com/facebook/lexical/pull/8482
- [lexical-playground] Chore: Drop FIXME #8348 Firefox ArrowDown workaround in Tables.spec.mjs by @markselby9 in https://github.com/facebook/lexical/pull/8508
- [Breaking Change][lexical-markdown] Bug Fix: Apply markdown shortcuts on composition-committed triggers by @mayrang in https://github.com/facebook/lexical/pull/8503
- [Breaking Change][lexical-extension][lexical-rich-text][lexical-plain-text] Feature: Remove empty inline elements by @levensta in https://github.com/facebook/lexical/pull/8497
- [lexical-table] Bug Fix: prevent crash when moving selection with arrow key outside of nested table by @randal-atticus in https://github.com/facebook/lexical/pull/8502
- [lexical][lexical-list][lexical-selection][lexical-link] Refactor: Centralize replace-area selection mapping + bulk splice by @mayrang in https://github.com/facebook/lexical/pull/8505
- [lexical-extension] Bug Fix: Set the correct default
$canIndentby @levensta in https://github.com/facebook/lexical/pull/8510 - [ci] Refactor: Use composite actions to simplify github workflows by @etrepum in https://github.com/facebook/lexical/pull/8504
- [lexical-website] Refactor: Drop docusaurus-plugin-internaldocs-fb preset by @zurfyx in https://github.com/facebook/lexical/pull/8516
- [lexical-website] Bug Fix: Drop Vercel Analytics inject and unwrap chat input from flex parent by @mayrang in https://github.com/facebook/lexical/pull/8509
- [lexical-code-shiki][nextjs-code-shiki] Bug Fix: Externalize shiki dependencies in the published bundle by @etrepum in https://github.com/facebook/lexical/pull/8514
- [lexical-website] Bug Fix: Correct links to included extensions by @duydang2311 in https://github.com/facebook/lexical/pull/8523
- [lexical-markdown] Bug Fix: run element markdown shortcuts on Enter by @abhinavgautam01 in https://github.com/facebook/lexical/pull/8488
- [lexical-react] Feature: optional async onClose for LexicalTypeaheadMenuPlugin by @abhinavgautam01 in https://github.com/facebook/lexical/pull/8489
- [lexical][lexical-yjs][lexical-playground] Chore: Respect browserslist by @levensta in https://github.com/facebook/lexical/pull/8512
- [ci] Chore: pin Windows e2e runners to windows-2022 by @etrepum in https://github.com/facebook/lexical/pull/8522
- [lexical-playground] Bug Fix: Fix unawaited playwright promises in e2e test suite by @etrepum in https://github.com/facebook/lexical/pull/8521
- [lexical-yjs] Chore: Fix RenderSnapshot comment typo by @LeSingh1 in https://github.com/facebook/lexical/pull/8527
- [lexical-rich-text] Bug Fix: Insert paragraph on Enter for a block DecoratorNode NodeSelection by @mayrang in https://github.com/facebook/lexical/pull/8526
- [Breaking Change][lexical][lexical-extension][lexical-rich-text][lexical-plain-text] Feature: Move triple click selection handling to NormalizeTripleClickSelectionExtension by @etrepum in https://github.com/facebook/lexical/pull/8520
- [lexical] Bug Fix: handle triple-click overselection in
$setBlocksTypeby @flavorjones in https://github.com/facebook/lexical/pull/8517 - [lexical-website] Bug Fix: Remove embed=1 from non-iframe StackBlitz links by @etrepum in https://github.com/facebook/lexical/pull/8531
- [lexical-markdown] Bug Fix: Fix Markdown import with Unicode whitespace by @rodrigolungui in https://github.com/facebook/lexical/pull/8535
- [lexical] Feature: ElementNode import/export support for data-lexical-indent by @etrepum in https://github.com/facebook/lexical/pull/8536
- [lexical-history] Feature: Add maxDepth option to HistoryExtension by @etrepum in https://github.com/facebook/lexical/pull/8537
- build(deps): bump serialize-javascript from 6.0.2 to 7.0.4 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8540
- [lexical-playground] Bug Fix: EquationNode click → NodeSelection + empty-input Backspace removes by @mayrang in https://github.com/facebook/lexical/pull/8534
- [lexical] Feature: Detect infinite recursion in update listeners by @mayrang in https://github.com/facebook/lexical/pull/8542
- [lexical-extension][lexical-html][lexical-utils][lexical] Chore: Migrate away from legacy flow syntax by @SamChou19815 in https://github.com/facebook/lexical/pull/8547
- [lexical-markdown] Chore: Cover bold italic markdown round trip by @rohan-patnaik in https://github.com/facebook/lexical/pull/8541
- [lexical] Bug Fix: Cache last-child kind for trailing-
reconcile by @mayrang in https://github.com/facebook/lexical/pull/8548 - [lexical-playground] Bug Fix: Normalize collapsible content children by @rohan-patnaik in https://github.com/facebook/lexical/pull/8539
- [lexical-extension][lexical-playground] Feature: Insert paragraph on click after the last block by @mayrang in https://github.com/facebook/lexical/pull/8549
- [lexical-code-prism][lexical-code-shiki][lexical-playground] Feature: Allow null Tokenizer.defaultLanguage to preserve markdown ``` round-trip by @mayrang in https://github.com/facebook/lexical/pull/8553
- [lexical][lexical-rich-text][lexical-code-core] Bug Fix: Cursor stuck before leading inline DecoratorNode by @mayrang in https://github.com/facebook/lexical/pull/8558
- [lexical] Bug Fix: Skip $reconcileChildren fast path during full reconcile by @etrepum in https://github.com/facebook/lexical/pull/8564
- [lexical-playground] Bug Fix: Build dev playground in development mode by @etrepum in https://github.com/facebook/lexical/pull/8565
- [Breaking Change][lexical][lexical-html][lexical-selection][lexical-utils][lexical-playground] Feature: Generalize DOMSlot and add DOMRenderExtension override surface by @mayrang in https://github.com/facebook/lexical/pull/8519
- [lexical-website] Bug Fix: Fix crash on /docs/error page from undefined process by @etrepum in https://github.com/facebook/lexical/pull/8557
- [lexical] Bug Fix: Correct children fast-path text size for cross-parent-moved elements by @etrepum in https://github.com/facebook/lexical/pull/8569
- [ci] Use playwright install-deps instead of apt-get by @etrepum in https://github.com/facebook/lexical/pull/8572
- [lexical-website] Feature: Server-rendered "Copy page" Markdown button by @etrepum in https://github.com/facebook/lexical/pull/8570
- [lexical-html] Feature: DOMImportExtension - replacement for importDOM by @etrepum in https://github.com/facebook/lexical/pull/8528
- [lexical-website] Documentation: Tuning HistoryExtension for long sessions by @etrepum in https://github.com/facebook/lexical/pull/8546
- [*] Refactor: Publish packages from their root directory by @etrepum in https://github.com/facebook/lexical/pull/8554
- fix: prevent MOVE_TO_END/MOVE_TO_START crash on decorator-only edits by @potatowagon in https://github.com/facebook/lexical/pull/8577
- [lexical-html][lexical-playground] Feature: Conditional DOM render overrides (disabledForEditor/disabledForSession) by @etrepum in https://github.com/facebook/lexical/pull/8575
- fix: restore Shift+Cmd+Arrow selection expansion for MOVE_TO_END/MOVE_TO_START by @potatowagon in https://github.com/facebook/lexical/pull/8581
- [ci][lexical] Bug Fix: Upgrade @playwright/test to ^1.60.0 by @etrepum in https://github.com/facebook/lexical/pull/8582
- @rhagigi made their first contribution in https://github.com/facebook/lexical/pull/8422
- @markselby9 made their first contribution in https://github.com/facebook/lexical/pull/8430
- @abhishekvishwakarma007 made their first contribution in https://github.com/facebook/lexical/pull/8428
- @nmggithub made their first contribution in https://github.com/facebook/lexical/pull/8417
- @danyalahmed1995 made their first contribution in https://github.com/facebook/lexical/pull/8487
- @kotom320 made their first contribution in https://github.com/facebook/lexical/pull/8475
- @duydang2311 made their first contribution in https://github.com/facebook/lexical/pull/8523
- @abhinavgautam01 made their first contribution in https://github.com/facebook/lexical/pull/8488
- @LeSingh1 made their first contribution in https://github.com/facebook/lexical/pull/8527
- @flavorjones made their first contribution in https://github.com/facebook/lexical/pull/8517
- @rodrigolungui made their first contribution in https://github.com/facebook/lexical/pull/8535
- @rohan-patnaik made their first contribution in https://github.com/facebook/lexical/pull/8541
Full Changelog: https://github.com/facebook/lexical/compare/v0.44.0...v0.45.0
v0.44.0
v0.44.0 is a monthly release with a few minor breaking changes (deprecations), a notable new experimental DOMRenderExtension API for overriding DOM create/update/export, easier to use priority levels for registering commands, a pagination demonstration and convenient html import/export in the playground, better drag and drop support, automatic inline of CSS for HTML import, consistent CSP-safe style updates, and a wide range of bug fixes and other new features.
OffsetView / $createOffsetView never worked correctly, has no documentation, no tests, and no usage in the monorepo. It has been deprecated. The only function still in use, $createChildrenArray, is now exported from lexical itself — import it from lexical rather than @lexical/offset going forward.
The "press Enter three times to exit a CodeNode" logic has moved from CodeNode.insertNewAfter to a KEY_ENTER_COMMAND listener registered by CodeExtension. This fixes paste-with-blank-lines incorrectly escaping the code block. Using CodeNode without CodeExtension is now deprecated — a backwards-compatible shim with a dev-mode warning is in place, but the node is expected to stop working without CodeExtension in a future version.
A new DOMRenderExtension (in @lexical/html) and EditorDOMRenderConfig (in lexical) parameterize $createDOM, $updateDOM, $exportDOM, $getDOMSlot, $shouldInclude, and $shouldExclude so that node rendering and export can be overridden via composable middleware. Use domOverride(nodes, config) to target one or more node classes, predicates, or '*' (wildcard), and call $next() from inside an override to delegate to the underlying implementation.
A new $decorateDOM(nextNode, prevNode, dom, editor) hook runs after a node is created/updated and after its children have been reconciled, intended for in-place attribute or DOM tweaks. Override ordering is a well-defined topological sort: wildcards highest, then predicates, then class hierarchy (subclass before superclass), with extension dependency order and registration order as tiebreakers.
Render-context APIs are also exposed: $withRenderContext, $getRenderContextValue, contextValue, contextUpdater, RenderContextRoot, RenderContextExport. New traversal helpers $generateDOMFromNodes and $generateDOMFromRoot populate a container using the configured render config. CreateEditorArgs.dom accepts a Partial<EditorDOMRenderConfig> to override rendering at editor creation. $isLexicalNode is also exported from lexical.
Five new command priorities — COMMAND_PRIORITY_BEFORE_EDITOR, _BEFORE_LOW, _BEFORE_NORMAL, _BEFORE_HIGH, _BEFORE_CRITICAL — register listeners that run most-recently-registered first, in front of the existing first-registered-first listeners at the same priority. Ordering is: highest priority first, then all BEFORE_* listeners (LIFO), then legacy listeners (FIFO). The new priorities are almost always what you want for new code; legacy priorities are unchanged so this is purely additive. See the new "Priorities and ordering" docs.
Both packages now export proper extensions (CodePrismExtension, CodeShikiExtension) with {disabled, tokenizer} signal-based configuration that can be toggled and hot-swapped at runtime. The legacy CodeHighlighterShikiExtension is kept as a deprecated backwards-compatible shim.
AutoLinkExtension, registerAutoLink, and LexicalAutoLinkPlugin now accept an optional punctuation setting to override the default boundary characters (e.g. to allow colon-delimited matches without breaking URLs that contain colons).
SplitAtPointCaretNextOptions (used by $insertNodeToNearestRootAtCaret and $splitAtPointCaretNext) gains a removeEmptyDestination option for finer control over whether an empty destination is replaced entirely.
New $handleRichTextDrop and $handlePlainTextDrop helpers implement Lexical-aware text drag-and-drop, including same-block drags, cross-TextNode and cross-block drops, DecoratorNode preservation, and cross-editor drags. registerRichText and registerPlainText now wire these by default.
@lexical/extension (since v0.36.1, Sep 2025) and the NodeState API in lexical (since v0.26.0, Feb 2025) are now formally stable.
@lexical/offsetOffsetView/$createOffsetView(use$createChildrenArrayfromlexical) (#8350)@lexical/text$findTextIntersectionFromCharacters— broken, untested, undocumented (#8364)CodeHighlighterShikiExtension/CodeHighlighterShikiConfig(useCodeShikiExtension) (#8346)- Using
CodeNodewithoutCodeExtension(#8360)
Core:
⚠️ #8350 DeprecateOffsetView; export$createChildrenArrayfromlexical- 🆕 #8353 #8368
EditorDOMRenderConfig,DOMRenderExtension,domOverride,$decorateDOM, render context,$generateDOMFromNodes,$generateDOMFromRoot,$isLexicalNode,CreateEditorArgs.dom - 🆕 #8375
COMMAND_PRIORITY_BEFORE_*priorities for last-registered-called-first ordering - 🧹 #8354 Remove
@experimentalfrom Extension and NodeState APIs - ✅ #8356 Workaround for synchronous Firefox focus edge case where deferred callbacks were silently discarded
- ✅ #8349 Resolve Firefox arrow-key navigation skipping over collapsible content
- ✅ #8361 Fall back to non-shifted key matching for Option+number shortcuts on macOS
Clipboard / Rich Text / Plain Text:
- ✅ #8373 Drag-and-drop within the same block now correctly moves the dragged text;
DecoratorNodes and formatting are preserved across drops; cross-editor drags work even with two Lexical versions on the same page
Code:
⚠️ #8360 Move three-Enter code-block escape logic to aKEY_ENTER_COMMANDlistener inCodeExtension; fixes blank-line paste escaping the code block- 🆕 #8346 Add
CodePrismExtension(@lexical/code-prism) andCodeShikiExtension(@lexical/code-shiki) - 🧹 #8330 Upgrade
shikito^4.0.2
Extension:
- ✅ #8328 Remove JSX/
reacttype dependency fromDecoratorTextNode - ✅ #8377
LexicalExtensionEditorComposerno longer disposes the editor on unmount; lifetime is the caller's responsibility (fixes nested/caption editors after remount)
HTML / Table:
- 🆕 #8326 Inline CSS from
<style>tags during HTML import (fixes paste from Excel, Outlook, etc.) - ✅ #8313 Merge nested lists into the parent
<li>during HTML export, eliminating duplicate ordered-list numbering
Link:
- 🆕 #8378 Allow custom punctuation for AutoLink boundaries
List:
- ✅ #8382 Ensure
ListItemNodealways has aListNodeparent (orphans are merged or floated to root) - ✅ #8390 Toggle checklist items on mobile tap (iOS Safari / Android Chrome) via
pointerup - ✅ #8313 Merge nested lists into parent
<li>on HTML export
Markdown:
- ✅ #8332 Replace negative lookbehind assertions for Safari < 16.4 compatibility
- ✅ #8365 Add an undo history entry for markdown shortcut transforms so undo no longer also undoes the triggering keystroke
- ✅ #8311 Escape ordered-list pattern (
\d+\.) inside bullet/check list item exports to fix double-escape on round-trip - ✅ #8381 Code spans take precedence over inline formatting in shortcut transforms (CommonMark behavior)
Playground:
- 🆕 #8322 New
PagesExtensionwithPageNode,PageContentNode,PageSetupNodefor paginated documents and print-friendly output - 🆕 #8323 Animations for collapsible section expand/collapse and arrow rotation
- 🆕 #8379 #8386 "Convert to HTML" toolbar button (round-trips through
$generateHtmlFromNodes/$generateNodesFromDOM); HTML view formatted with prettier - 🆕 #8346 Migrate eight playground plugins to extensions (
PageBreak,Twitter,YouTube,Figma,TabFocus,Collapsible,SpecialText, code-highlight) and remove the deadLinkPluginandStickyPluginfiles - ✅ #8385
NodeContextMenuPluginfalls back to the root node when the click target has no Lexical node, instead of showing an empty menu - ✅ #8388 Use
@floating-ui/reactforFloatingLinkEditorPluginpositioning; correctly handles all viewport boundaries and FirefoxfocusNode.parentElementquirks - ✅ #8392 Show floating link editor for single-character links (right-bias adjacent-link lookup)
React:
- ✅ #8329 Prevent error when
editorRefisnullinLexicalEditorRefPlugin - ✅ #8366 Add
yjsas an optional peer dependency for Yarn PnP compatibility - ✅ #8377 Don't auto-dispose editor from
LexicalExtensionEditorComposer - ✅ #8385 Root-node fallback in
NodeContextMenuPlugin
Text:
- 🧹 #8364 Add deprecation notice to
$findTextIntersectionFromCharacters
Utils:
- ✅ #8384 Clean up and test
$insertNodeToNearestRootAtCaretedge cases; addremoveEmptyDestinationtoSplitAtPointCaretNextOptions
Refactor (CSP-safe styles):
- 🧹 #8372 Replace runtime
cssText/setAttribute('style', …)writes with property-based style updates acrosslexical,@lexical/code-core,@lexical/list,@lexical/table,@lexical/yjs, and the playground
Website:
- 🆕 #8316 Add more examples to the demos gallery and statically capture screenshots with Playwright (replaces the third-party screenshot service)
- ✅ #8369 Fix tailwindcss docusaurus config regression (sync, not async)
- ✅ #8371 Add a dedicated
tsconfig.jsonforlexical-websiteso type errors are actually surfaced in CI
Infrastructure:
- 🧹 #8341 Encourage agents to use extensions and
$configin AGENTS.md - 🧹 #8355 Refactor CommonJS scripts to ESM modules
- 🧹 #8357 Cache build + Playwright before running e2e tests
- 🧹 #8324 Override
yamlto>=1.10.3to fix CVE-2026-33532 - 🧹 #8358 Address
simple-gitdependency vulnerability - 🧹 #8380 Address
follow-redirectsdependency vulnerability - 🧹 #8334 Remove example/fixture lockfiles from git to reduce Dependabot noise
- 🧹 #8336 #8347 Update stale dev dependencies to resolve Dependabot alerts
- v0.43.0 by @etrepum in https://github.com/facebook/lexical/pull/8319
- [lexical-website] Feature: Add more examples to the demos gallery with local screenshot captures by @etrepum in https://github.com/facebook/lexical/pull/8316
- Update examples for v0.43.0 by @etrepum in https://github.com/facebook/lexical/pull/8321
- [lexical-playground]: Collapsible Section Animations by @ivailop7 in https://github.com/facebook/lexical/pull/8323
- [*] Security: Override yaml to >=1.10.3 to fix CVE-2026-33532 by @potatowagon in https://github.com/facebook/lexical/pull/8324
- [lexical-extension] Fix: Remove JSX dependency from DecoratorTextNode by @etrepum in https://github.com/facebook/lexical/pull/8328
- [lexical-react] Bug Fix: Prevent error when editorRef is null by @Jimmy89 in https://github.com/facebook/lexical/pull/8329
- [lexical-code-shiki] Chore: Upgrade shiki to ^4.0.2 by @etrepum in https://github.com/facebook/lexical/pull/8330
- [lexical-markdown] Bug Fix: replace lookbehind assertions for Safari < 16.4 compatibility by @Yahid-Basha in https://github.com/facebook/lexical/pull/8332
- chore: remove example/fixture lockfiles from git to reduce Dependabot noise by @thatmichael85 in https://github.com/facebook/lexical/pull/8334
- chore: update stale dev dependencies to resolve Dependabot alerts by @thatmichael85 in https://github.com/facebook/lexical/pull/8336
- build(deps): bump @docusaurus/faster from 3.9.2 to 3.10.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8342
- build(deps): bump semver from 7.7.2 to 7.7.4 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8338
- build(deps): bump y-websocket from 1.5.4 to 3.0.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8343
- build(deps): bump @docusaurus/* from 3.9.2 to 3.10.0, update typedoc, react by @dependabot[bot] in https://github.com/facebook/lexical/pull/8339
- [*] Chore: Encourage agents to use extensions and $config in AGENTS.md by @etrepum in https://github.com/facebook/lexical/pull/8341
- [lexical-code-prism][lexical-code-shiki][lexical-playground] Feature: Add CodePrismExtension, CodeShikiExtension, and migrate playground plugins to extensions by @etrepum in https://github.com/facebook/lexical/pull/8346
- build(deps-dev): bump the dev-dependencies group across 1 directory with 42 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8347
- build(deps): bump zustand from 4.5.7 to 5.0.12 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8340
- [lexical-playground] Feature: Add PagesExtension by @ibastawisi in https://github.com/facebook/lexical/pull/8322
- [lexical-html][lexical-table] Feature: Inline CSS from <style> tags by @tomsarduy in https://github.com/facebook/lexical/pull/8326
- build(deps): bump pnpm/action-setup from 4 to 6 in the github-actions group across 1 directory by @dependabot[bot] in https://github.com/facebook/lexical/pull/8335
- [Breaking Change][lexical-offset][lexical] Chore: Deprecate the broken/undocumented/untested OffsetView and export $createChildrenArray from lexical by @etrepum in https://github.com/facebook/lexical/pull/8350
- [lexical][lexical-extension] Chore: Remove @experimental flag from Extension and NodeState APIs by @etrepum in https://github.com/facebook/lexical/pull/8354
- [lexical] Bug Fix: Resolve Firefox arrow key navigation issue in collapsible nodes (#8348) by @MohmedIkram in https://github.com/facebook/lexical/pull/8349
- [*] Chore: Cache build + playwright before running e2e tests by @etrepum in https://github.com/facebook/lexical/pull/8357
- [lexical] Bug Fix: Workaround for synchronous firefox focus edge case behavior by @etrepum in https://github.com/facebook/lexical/pull/8356
- address simple-git dependency vulnerability by @potatowagon in https://github.com/facebook/lexical/pull/8358
- [lexical][lexical-playground] Fix: Use the fallback matching for number keys in keyboard shortcuts by @levensta in https://github.com/facebook/lexical/pull/8361
- [Breaking Change][lexical-code] Bug Fix: move code block escape logic to KEY_ENTER_COMMAND listener by @anikakpillai in https://github.com/facebook/lexical/pull/8360
- [*] Chore: Refactor CommonJS scripts to ESM modules by @etrepum in https://github.com/facebook/lexical/pull/8355
- [lexical-text] Chore: Add deprecation notice to $findTextIntersectionFromCharacters by @etrepum in https://github.com/facebook/lexical/pull/8364
- [lexical-markdown] Bug Fix: Add undo history entry for markdown shortcut transforms by @kimseongyu in https://github.com/facebook/lexical/pull/8365
- [lexical-react] Bug Fix: Add 'yjs' as optional peer dependency for Yarn PnP compatibility by @grapgrap in https://github.com/facebook/lexical/pull/8366
- [lexical][lexical-html] Feature: Extensible DOM create/update/export by @etrepum in https://github.com/facebook/lexical/pull/8353
- [lexical-website] Bug Fix: Fix tailwindcss docusaurus config regression by @etrepum in https://github.com/facebook/lexical/pull/8369
- [lexical-website] Bug Fix: Fix type checking for lexical-website package by @etrepum in https://github.com/facebook/lexical/pull/8371
- [lexical-react] Bug Fix: Don't auto-dispose editor from LexicalExtensionEditorComposer by @etrepum in https://github.com/facebook/lexical/pull/8377
- [lexical] Feature:
COMMAND_PRIORITY_BEFORE_*priorities for last-registered-called-first order by @etrepum in https://github.com/facebook/lexical/pull/8375 - [lexical-markdown] Bug Fix: Escape ordered-list pattern in bullet list item export by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8311
- address follow-redirects dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8380
- [lexical-playground] Feature: HTML conversion button by @levensta in https://github.com/facebook/lexical/pull/8379
- [lexical-markdown] Bug Fix: Code spans take precedence over inline formatting in shortcuts by @potatowagon in https://github.com/facebook/lexical/pull/8381
- [lexical-list] Bug Fix: Ensure that ListItemNode always has a ListItem parent by @etrepum in https://github.com/facebook/lexical/pull/8382
- [lexical][lexical-code-core][lexical-list][lexical-table][lexical-yjs] Refactor: make runtime style updates CSP-safe by @holly-agyei in https://github.com/facebook/lexical/pull/8372
- [lexical-html][lexical-playground] Feature: Implement a well-defined ordering for DOMRenderExtension overrides and add $decorateDOM by @etrepum in https://github.com/facebook/lexical/pull/8368
- [lexical][lexical-utils][lexical-list] Bug Fix: Clean up and test $insertNodeToNearestRootAtCaret edge cases by @etrepum in https://github.com/facebook/lexical/pull/8384
- [lexical-clipboard][lexical-rich-text][lexical-plain-text] Bug Fix: Drag-and-drop within the same block by @etrepum in https://github.com/facebook/lexical/pull/8373
- [lexical-list] Bug Fix: Merge nested list into parent
- during HTML export by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8313
- [lexical-link][lexical-react] Feature: Allow custom punctuation for AutoLink boundaries by @holly-agyei in https://github.com/facebook/lexical/pull/8378
- [lexical-playground] Feature: Format HTML conversion with prettier by @etrepum in https://github.com/facebook/lexical/pull/8386
- [lexical-react] Bug Fix: Fall back to root node in NodeContextMenuPlugin when click target has no Lexical node by @mayrang in https://github.com/facebook/lexical/pull/8385
- build(deps): bump @excalidraw/excalidraw from 0.18.0 to 0.18.1 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8389
- [lexical-playground] Refactor: Use @floating-ui/react for FloatingLinkEditorPlugin positioning by @mayrang in https://github.com/facebook/lexical/pull/8388
- [lexical-list] Bug Fix: Toggle checklist items on mobile tap by @jWA86 in https://github.com/facebook/lexical/pull/8390
- [lexical-playground] Bug Fix: Show floating link editor for single-character links by @mayrang in https://github.com/facebook/lexical/pull/8392
- [lexical-extension] Bug Fix: Use maybeFromEditor in getPeerDependencyFromEditor by @potatowagon in https://github.com/facebook/lexical/pull/8398
- [*] Fix Flow type errors in flow definition files by @potatowagon in https://github.com/facebook/lexical/pull/8396
- [lexical] Chore: Fix uuid dependency vulnerability by @vishisht31 in https://github.com/facebook/lexical/pull/8399
- [lexical-website] Set prettier arrowParens to avoid by @potatowagon in https://github.com/facebook/lexical/pull/8397
- @Jimmy89 made their first contribution in https://github.com/facebook/lexical/pull/8329
- @Yahid-Basha made their first contribution in https://github.com/facebook/lexical/pull/8332
- @tomsarduy made their first contribution in https://github.com/facebook/lexical/pull/8326
- @MohmedIkram made their first contribution in https://github.com/facebook/lexical/pull/8349
- @anikakpillai made their first contribution in https://github.com/facebook/lexical/pull/8360
- @grapgrap made their first contribution in https://github.com/facebook/lexical/pull/8366
- @vishisht31 made their first contribution in https://github.com/facebook/lexical/pull/8380
- @holly-agyei made their first contribution in https://github.com/facebook/lexical/pull/8372
- @mayrang made their first contribution in https://github.com/facebook/lexical/pull/8385
- @jWA86 made their first contribution in https://github.com/facebook/lexical/pull/8390
Full Changelog: https://github.com/facebook/lexical/compare/v0.43.0...v0.44.0
v0.43.0
v0.43.0 is a monthly release with a minor breaking change, new features, and a number of bug fixes across selection, tables, markdown, and extensions. Notable highlights include a new useExtensionSignalValue hook, and CSS theme options for Yjs collaboration cursors.
Outside of the release artifact, we've refreshed the lexical.dev website thanks to @m-santanna (and inspired by design mockups from @ixahmedxi). Importantly this refresh includes a set of modern examples (examples/website-* and examples/agent-example) that are embedded on the front page and showcase current best practices.
Asynchronous parent editor delegation #8308
@lexical/react nested editors now use asynchronous parent editor delegation when needed to match pre-0.42.0 legacy behavior.
@lexical/react - useExtensionSignalValue #8286
A new @lexical/react/useExtensionSignalValue module is available for reading signal values from extension output within React components
Core:
⚠️ #8308 Use asynchronous parent editor delegation when needed in nested editors- ✅ #8267 Exclude Android WebView from
IS_SAFARIbrowser detection - ✅ #8273 Fix merging
TextNodes when__statecontains a different number of default values - ✅ #8266 Replace
$insertNodeswith$insertNodeIntoLeaffor consistentDecoratorNodebehavior insideMarkNode
Code:
- ✅ #8254 Remove usage of
skipTransformsinCodeHighlighterPrismandCodeHighlighterShiki
Extension:
- 🆕 #8286 Add
@lexical/react/useExtensionSignalValuemodule for reading signals from React
Examples:
- 🆕 #8281 Add a new agent example using a local LLM (Transformers.js / in-browser)
- 🆕 #8258 Add additional website examples
Headless:
- ✅ #8274 Use
window.happyDOM.close()to ensure proper cleanup
Link:
- ✅ #8309 Preserve cursor position when merging adjacent identical links
Markdown:
- ✅ #8265 Preserve hard line breaks during import when newlines are preserved
Playground:
- ✅ #8260 Use
isExactShortcutMatchfor Dvorak keyboard compatibility
Selection:
- ✅ #8261 Make
$getSelectionStyleValueForPropertydirection-independent
Table:
- ✅ #8259 Infer column header state from position during DOM import
Utils:
- ✅ #8276 Fix
$insertNodeIntoLeafedge case; update@preact/signals-core, hermes, and flow dependencies
Yjs:
- 🆕 #8271 Add CSS classes to collaboration cursor elements
Infrastructure:
- 🧹 #8287 Upgrade ESLint 8 → ESLint 10 with flat configuration
- 🧹 #8307 Upgrade Vite to
^7.3.2 - 🧹 #8248 Update GitHub CI workflows and run with Node 24
- 🧹 #8253 Update
flow-binto 0.306.0 and add incompatible-variance workaround - 🧹 #8277 #8315 Bump Flow and replace legacy Flow syntax with modern equivalents
- 🧹 #8243 Update unit tests with extensions to use explicit resource management (
using)
- v0.42.0 by @etrepum in https://github.com/facebook/lexical/pull/8245
- build(deps): bump next from 15.5.11 to 15.5.14 in /scripts/tests/integration/fixtures/lexical-esm-nextjs by @dependabot[bot] in https://github.com/facebook/lexical/pull/8242
- [examples] Chore: Update examples for v0.42.0 by @etrepum in https://github.com/facebook/lexical/pull/8246
- [*] Chore: Update unit tests with extensions to use explicit resource management (using) by @etrepum in https://github.com/facebook/lexical/pull/8243
- [*] Chore: Github CI workflows action updates and run with node 24 by @etrepum in https://github.com/facebook/lexical/pull/8248
- [*] Chore: Update flow-bin to 0.306.0 and add incompatible-variance workaround by @etrepum in https://github.com/facebook/lexical/pull/8253
- [lexical-code-prism][lexical-code-shiki] Bug Fix: Remove usage of skipTransforms in CodeHighlighterPrism and CodeHighlighterShiki by @etrepum in https://github.com/facebook/lexical/pull/8254
- build(deps): bump astro from 5.18.0 to 5.18.1 in /scripts/tests/integration/fixtures/lexical-esm-astro-react by @dependabot[bot] in https://github.com/facebook/lexical/pull/8262
- [lexical-selection] Bug Fix: Make $getSelectionStyleValueForProperty direction-independent by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8261
- [lexical-table] Bug Fix: Infer column header state from position during DOM import by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8259
- build(deps): bump happy-dom from 20.0.11 to 20.8.8 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8264
- [lexical-playground] Bug Fix: Use isExactShortcutMatch for Dvorak keyboard compatibility by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8260
- [lexical] Fix: exclude Android WebView from IS_SAFARI browser detection by @kzroo in https://github.com/facebook/lexical/pull/8267
- [examples] Feature: Added examples (for the website) by @m-santanna in https://github.com/facebook/lexical/pull/8258
- [lexical] Fix : Replaced the function $insertNodes with $insertNodeIntoLeaf for consistent behavior of Decorator Node within MarkNode by @Jynx2004 in https://github.com/facebook/lexical/pull/8266
- build(deps): bump happy-dom from 20.8.8 to 20.8.9 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8269
- [lexical-website] Feature: ui improvement in the homepage of lexical.dev by @m-santanna in https://github.com/facebook/lexical/pull/8216
- [lexical] Fix: merge TextNodes when __state contains different number of default values by @james-atticus in https://github.com/facebook/lexical/pull/8273
- [lexical-headless] Bug Fix: Use window.happyDOM.close() to ensure proper cleanup by @etrepum in https://github.com/facebook/lexical/pull/8274
- Bump flow and replace legacy flow syntax with modern ones by @SamChou19815 in https://github.com/facebook/lexical/pull/8277
- [lexical-markdown] Bug Fix: Preserve markdown hard line breaks during import when newlines are preserved by @joshjryan in https://github.com/facebook/lexical/pull/8265
- [lexical-website] Chore: community page updates by @etrepum in https://github.com/facebook/lexical/pull/8270
- [lexical-utils][lexical-extension][*] Bug Fix: Fix $insertNodeIntoLeaf edge case and update @preact/signals-core, hermes, and flow related dependencies by @etrepum in https://github.com/facebook/lexical/pull/8276
- build(deps): bump lodash-es from 4.17.22 to 4.18.1 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8279
- [lexical-yjs] Feature: Add CSS classes to collaboration cursor elements by @m-brtn in https://github.com/facebook/lexical/pull/8271
- [example] Feature: Add a new agent-example using a local LLM by @etrepum in https://github.com/facebook/lexical/pull/8281
- [lexical-react] Feature: Add @lexical/react/useExtensionSignalValue module for reading signals by @etrepum in https://github.com/facebook/lexical/pull/8286
- [lexical-website] Documentation Update: clarify Yjs custom node property syncing by @Vedthakar in https://github.com/facebook/lexical/pull/8288
- [lexical] Chore: Upgrade ESLint 8 to ESLint 10 with flat configuration by @etrepum in https://github.com/facebook/lexical/pull/8287
- [*] Chore: Upgrade vite to ^7.3.2 by @etrepum in https://github.com/facebook/lexical/pull/8307
- [Breaking Change][lexical] Bug Fix: Use asynchronous parent editor delegation when needed by @etrepum in https://github.com/facebook/lexical/pull/8308
- [lexical-link] Bug Fix: Preserve cursor position when merging adjacent identical links by @Sathvik-Chowdary-Veerapaneni in https://github.com/facebook/lexical/pull/8309
- [*] Fix: Replace legacy Flow syntax with modern equivalents in .flow … by @potatowagon in https://github.com/facebook/lexical/pull/8315
- @Sathvik-Chowdary-Veerapaneni made their first contribution in https://github.com/facebook/lexical/pull/8261
- @kzroo made their first contribution in https://github.com/facebook/lexical/pull/8267
- @joshjryan made their first contribution in https://github.com/facebook/lexical/pull/8265
- @m-brtn made their first contribution in https://github.com/facebook/lexical/pull/8271
- @Vedthakar made their first contribution in https://github.com/facebook/lexical/pull/8288
Full Changelog: https://github.com/facebook/lexical/compare/v0.42.0...v0.43.0