Download Latest Version v0.48.0 source code.zip (7.7 MB)
Email in envelope

Get an email when there's a new version of Lexical

Home / v0.45.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-05-28 37.1 kB
v0.45.0 source code.tar.gz 2026-05-28 5.8 MB
v0.45.0 source code.zip 2026-05-28 6.8 MB
Totals: 3 Items   12.6 MB 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.

Breaking Changes

lexical — Shadow root inclusion in $getReconciledDirection (#8479)

$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.

lexical / @lexical/rich-text — Backspace at block start preserves the current block (#8493)

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.

lexical — Selection adjustment in removeFromParent callers (#8501)

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.

@lexical/markdown — Apply markdown shortcuts on composition-committed triggers (#8503)

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-textNormalizeInlineElementsExtension (#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-textNormalizeTripleClickSelectionExtension (#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.

New APIs

@lexical/htmlDOMImportExtension (experimental) (#8528)

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.

@lexical/html / @lexical/playground — Conditional DOM render overrides (#8575)

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.

lexicalElementNode import/export of data-lexical-indent (#8536)

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).

lexical — Infinite recursion detection in update listeners (#8542)

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.

@lexical/historycanUndo / canRedo ReadonlySignals (#8465)

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.

@lexical/historymaxDepth option (#8537)

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.

@lexical/markdown$convertSelectionToMarkdownString (#8395)

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.

lexical / @lexical/list$setFormatFromDOM (#8460)

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.

@lexical/listListNode.createListItemNode (#8427)

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.

@lexical/rich-textescapeFormatTriggers on RichTextExtension (#8383)

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.

@lexical/extension / @lexical/playgroundClickAfterLastBlockExtension (#8549)

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.

@lexical/code-prism / @lexical/code-shikinull Tokenizer.defaultLanguage (#8553)

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.

@lexical/react — Optional async onClose for LexicalTypeaheadMenuPlugin (#8489)

LexicalTypeaheadMenuPlugin's onClose may now return a Promise, useful for handlers that need to await network or animation work before tearing down the menu.

@lexical/clipboardGetClipboardDataExtension export (#8431)

GetClipboardDataExtension is now exported from @lexical/clipboard for use as a peer dependency from custom clipboard handlers.

@lexical/website — Server-rendered "Copy page" Markdown button (#8570)

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.

Highlights

Core:

  • ⚠️ [#8479] Include shadow root in $getReconciledDirection
  • ⚠️ [#8493] Backspace at block start now preserves the current block (heading / list item / quote)
  • ⚠️ [#8501] Adjust selection when LexicalNode callers move a node out of its parent
  • ⚠️ [#8519] Generalize DOMSlot and add DOMRenderExtension override surface; markSelection rewritten on top
  • ⚠️ [#8520] Move triple-click selection normalization to NormalizeTripleClickSelectionExtension
  • 🆕 [#8536] ElementNode import/export of data-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 NodeMap and reconciler keyToDOMMap
  • ⚡ [#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 dir attribute in importDOM
  • ✅ [#8417] Workarounds for buggy browser behavior around macOS text replacements
  • ✅ [#8428] Respect CSS display style in isBlockDomNode / isInlineDomNode
  • ✅ [#8441] Reuse DOM when reconciling cross-parent node moves
  • ✅ [#8466] Resolve --lexical-indent-base-value via CSS var() instead of pre-computing in JS
  • ✅ [#8470] Preserve queued updates and tags through setRootElement
  • ✅ [#8475] Handle iOS 10-key Korean IME deleteContentBackward with targetRange
  • ✅ [#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 $reconcileChildren fast path during full reconcile
  • ✅ [#8569] Correct children fast-path text size for cross-parent-moved elements
  • ✅ [#8577] Prevent MOVE_TO_END / MOVE_TO_START crash on decorator-only elements
  • ✅ [#8581] Restore Shift+Cmd+Arrow selection expansion for MOVE_TO_END / MOVE_TO_START

HTML / DOM:

  • 🆕 [#8528] DOMImportExtension — composable replacement for importDOM with rule-based matchers and DOM preprocessing
  • 🆕 [#8575] disabledForEditor / disabledForSession predicates on domOverride

Code:

  • 🆕 [#8445] Outdent space-indented code lines on Shift+Tab
  • 🆕 [#8553] Allow null Tokenizer.defaultLanguage to 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 / canRedo ReadonlySignals on HistoryExtension
  • 🆕 [#8537] maxDepth option for bounding the undo stack

Link / List:

  • 🆕 [#8460] $setFormatFromDOM; ListItemNode imports alignment from DOM
  • 🆕 [#8427] ListNode.createListItemNode factory for subclasses

Markdown:

  • ⚠️ [#8503] Apply markdown shortcuts on composition-committed triggers (fixes IME-typed */_/~)
  • 🆕 [#8395] $convertSelectionToMarkdownString API
  • ✅ [#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 onClose for LexicalTypeaheadMenuPlugin
  • ✅ [#8411] Pass editor context to editorState.read() in markSelection
  • ✅ [#8472] ExtensionComponent support for output components with required props
  • 🧹 [#8485] Make onOpenEmbedModalForConfig prop optional in LexicalAutoEmbedPlugin

Rich Text / Plain Text:

  • 🆕 [#8383] Opt-in escapeFormatTriggers on RichTextExtension
  • ✅ [#8526] Insert paragraph on Enter for a block DecoratorNode NodeSelection

Table:

  • ✅ [#8492] Attach window pointerdown handler 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 RenderSnapshot comment typo

Playground:

  • 🆕 [#8464] New "markdown-editor split-view" example
  • ✅ [#8419] [#8432] Position FloatingLinkEditor correctly for multi-line / decorator-only links and near the editor's bottom edge
  • ✅ [#8442] Prevent crash importing <details> with loose body content
  • ✅ [#8444] Allow PagesExtension to be disabled by ActionsPlugin (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-size for h2
  • ✅ [#8521] Fix unawaited Playwright promises in e2e suite
  • ✅ [#8534] EquationNode click → 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 editorState null vs undefined and empty-state pitfall
  • 🆕 [#8467] Document NodeState in $config JSON serialization
  • 🆕 [#8471] TSDoc for LexicalNodeReplacement and withKlass
  • 🆕 [#8476] Add missing @lexical/react plugin docs
  • 🧹 [#8430] Inline toolbar SVG icons in examples via Vite asset handling
  • 🧹 [#8403] Merge dev-node-state-style into examples/node-state-style
  • 🧹 [#8473] Disable skipLibCheck in react-rich for 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-fb preset
  • ✅ [#8523] Correct links to included extensions
  • ✅ [#8531] Remove embed=1 from non-iframe StackBlitz links
  • ✅ [#8557] Fix crash on /docs/error page from undefined process

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 ArrowDown workaround in Tables.spec.mjs
  • 🧹 [#8522] Pin Windows e2e runners to windows-2022
  • 🧹 [#8572] Use playwright install-deps instead of apt-get
  • 🧹 [#8582] Upgrade @playwright/test to ^1.60.0
  • 🧹 [#8541] Cover bold-italic markdown round trip
  • 🧹 [#8400] Fix release workflow's missing rename from release.js to release.mjs
  • 🧹 [#8401] [#8404] [#8405] [#8406] [#8408] [#8409] [#8415] [#8540] Dependency vulnerability fixes (protobufjs, dompurify, postcss, astro, eslint, immutable, path-to-regexp, serialize-javascript)

What's Changed

New Contributors

Full Changelog: https://github.com/facebook/lexical/compare/v0.44.0...v0.45.0

Source: README.md, updated 2026-05-28