v0.52.0
Graphify-Labs/graphifyv0.52.0Sep 28, 2026by etrepum
Upgrading?
AI Summary
Lexical v0.52.0 targets mobile text input fixes and moves towards Lexical 1.0 with markdown extension unification and headless editor support.
Key Highlights
- Unified Markdown configuration with MdastExtension
- HeadlessExtension for server-side processing and tests
- Selection timing changes with SELECTION_CHANGE_COMMAND
- Fixes for deletion, drag-and-drop, and mobile input
Breaking Changes
- SELECTION_CHANGE_COMMAND consistently runs before DOM reconciliation
- Default HTML export now honors DOMRenderExtension overrides
- LexicalNode.getCommonAncestor is removed
New Features
- Unified Markdown configuration and inherited export rules
- Import/export middleware through context.next()
- HeadlessExtension for buildEditorFromExtensions
Full Release Notes
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.
### Breaking Changes
* [`lexical`](https://lexical.dev/docs/api/modules/lexical) — **`SELECTION_CHANGE_COMMAND` consistently runs before DOM reconciliation**, inside the pending writable update. This includes automatic `NodeSelection` and `TableSelection` notifications 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 native `selectionchange` event. 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 a `COLLABORATION_TAG` or `HISTORIC_TAG` update 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. Use `registerUpdateListener` for UI that must respond to every commit, including content-only changes ([#9219](https://github.com/facebook/lexical/pull/9219), [selection timing guide](https://lexical.dev/docs/concepts/selection#selection-change-timing))
* [`lexical`](https://lexical.dev/docs/api/modules/lexical) / [`@lexical/html`](https://lexical.dev/docs/api/modules/lexical_html) — **Default HTML export now honors `DOMRenderExtension` `$createDOM` overrides.** This affects nodes that inherit `LexicalNode.exportDOM` or call `super.exportDOM(editor)`, including text and paragraphs. If an override was intended only for the live editor, review the HTML it now exports. Custom `exportDOM` implementations that create their own elements can still bypass this hook; `$updateDOM` and `$decorateDOM` remain reconciliation-only, and `$exportDOM` handles export-specific changes ([#9231](https://github.com/facebook/lexical/pull/9231))
* [`lexical`](https://lexical.dev/docs/api/modules/lexical) — **`LexicalNode.getCommonAncestor` is 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](https://github.com/facebook/lexical/pull/9238))
### Deprecations
* [`@lexical/mdast`](https://lexical.dev/docs/api/modules/lexical_mdast) — `MdastImportExtension` and `MdastExportExtension` are deprecated aliases of `MdastExtension`. Move configuration to `MdastExtension` and replace `MdastImportExtensionOutput` / `MdastExportExtensionOutput` with `MdastExtensionOutput`. The package is experimental, and these aliases are intended to remain for only one release ([#9198](https://github.com/facebook/lexical/pull/9198))
### New APIs & Features
* [`@lexical/mdast`](https://lexical.dev/docs/api/modules/lexical_mdast) — **Unified Markdown configuration and inherited export rules.** `MdastExtension` owns 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. A `TextNode` rule can therefore handle tabs and custom text subclasses without separate registrations ([#9198](https://github.com/facebook/lexical/pull/9198))
* [`@lexical/mdast`](https://lexical.dev/docs/api/modules/lexical_mdast) — **Import/export middleware through `context.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. Use `context.next()` to delegate: `null` retains 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](https://github.com/facebook/lexical/pull/9198))
* [`@lexical/headless`](https://lexical.dev/docs/api/modules/lexical_headless) — **`HeadlessExtension`** works with `buildEditorFromExtensions` for server-side processing and tests. It marks the editor as headless and prevents attaching a DOM root. Unlike `createHeadlessEditor`, it keeps listener registration methods available, so extensions that register root listeners can still be used ([#9249](https://github.com/facebook/lexical/pull/9249))
### Notable Fixes
**Selection & editing**
* Backspace over all text in the first block preserves the empty block and its type ([#9236](https://github.com/facebook/lexical/pull/9236)); select-all deletion restores an editable paragraph when the root still contains slots such as footnotes ([#9240](https://github.com/facebook/lexical/pull/9240)); line deletion correctly resolves endpoints inside text-bearing inline decorators ([#9247](https://github.com/facebook/lexical/pull/9247))
* Dropping dragged text on the edge of its own selection no longer deletes it ([#9241](https://github.com/facebook/lexical/pull/9241)); persistent selection highlights retain coverage across mixed font sizes and partially overlapping rectangles ([#9196](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/9251))
* `setEditorState` with a childless root warns and recovers to an empty paragraph in production. Development builds still report the invalid state through `onError` ([#9183](https://github.com/facebook/lexical/pull/9183))
**Performance & signals**
* Writable nodes are cached during pending updates, reducing repeated node-map lookups ([#9169](https://github.com/facebook/lexical/pull/9169))
* `@lexical/extension` raises its `@preact/signals-core` dependency to `^1.14.4`, fixing stale computed values after a batch changes a signal and restores its original value ([#9248](https://github.com/facebook/lexical/pull/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 `$config` schemas, NodeState, and HTML import/export through extensions ([#9237](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/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](https://github.com/facebook/lexical/pull/9204), [#9220](https://github.com/facebook/lexical/pull/9220))
* Playground Find & Replace calculates offsets correctly across decorators and slots ([#9186](https://github.com/facebook/lexical/pull/9186))
## What's Changed
* 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
## New Contributors
* @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
Related Repositories
public-apis/public-apis★ 491,123
A collective list of free APIs
NousResearch/hermes-agent★ 255,883
The agent that grows with you
yt-dlp/yt-dlp★ 199,986
A feature-rich command-line audio/video downloader
microsoft/markitdown★ 191,478
Python tool for converting files and office documents to Markdown.
Significant-Gravitas/AutoGPT★ 187,698
AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.