Skip to main content

@lexical/rich-text

Classes

HeadingNode

Defined in: packages/lexical-rich-text/src/index.ts:311

Extends

Constructors

Constructor

new HeadingNode(tag?, key?): HeadingNode

Defined in: packages/lexical-rich-text/src/index.ts:359

Parameters
tag?

HeadingTagType = 'h1'

key?

string

Returns

HeadingNode

Overrides

ElementNode.constructor

Methods

$config()

$config(): BaseStaticNodeConfig & object & StaticNodeTypeAccessor<"heading"> & StaticNodeConfigAccessor<{ extends: typeof ElementNode; importDOM: { h1: () => object; h2: () => object; h3: () => object; h4: () => object; h5: () => object; h6: () => object; p: (node) => { conversion: () => object; priority: 3; } | null; span: (node) => { conversion: () => object; priority: 3; } | null; }; }>

Defined in: packages/lexical-rich-text/src/index.ts:315

Override this to implement the new static node configuration protocol, this method is called directly on the prototype and must not depend on anything initialized in the constructor. Generally it should be a trivial implementation.

Returns

BaseStaticNodeConfig & object & StaticNodeTypeAccessor<"heading"> & StaticNodeConfigAccessor<{ extends: typeof ElementNode; importDOM: { h1: () => object; h2: () => object; h3: () => object; h4: () => object; h5: () => object; h6: () => object; p: (node) => { conversion: () => object; priority: 3; } | null; span: (node) => { conversion: () => object; priority: 3; } | null; }; }>

Example
class MyNode extends TextNode {
$config() {
return this.config('my-node', {extends: TextNode});
}
}
Overrides

ElementNode.$config

afterCloneFrom()

afterCloneFrom(prevNode): void

Defined in: packages/lexical-rich-text/src/index.ts:354

Perform any state updates on the clone of prevNode that are not already handled by the constructor call in the static clone method. If you have state to update in your clone that is not handled directly by the constructor, it is advisable to override this method but it is required to include a call to super.afterCloneFrom(prevNode) in your implementation. This is only intended to be called by $cloneWithProperties function or via a super call.

Parameters
prevNode

this

Returns

void

Example
class ClassesTextNode extends TextNode {
// Not shown: static getType, static importJSON, exportJSON, createDOM, updateDOM
__classes = new Set<string>();
static clone(node: ClassesTextNode): ClassesTextNode {
// The inherited TextNode constructor is used here, so
// classes is not set by this method.
return new ClassesTextNode(node.__text, node.__key);
}
afterCloneFrom(node: this): void {
// This calls TextNode.afterCloneFrom and LexicalNode.afterCloneFrom
// for necessary state updates
super.afterCloneFrom(node);
this.__addClasses(node.__classes);
}
// This method is a private implementation detail, it is not
// suitable for the public API because it does not call getWritable
__addClasses(classNames: Iterable<string>): this {
for (const className of classNames) {
this.__classes.add(className);
}
return this;
}
addClass(...classNames: string[]): this {
return this.getWritable().__addClasses(classNames);
}
removeClass(...classNames: string[]): this {
const node = this.getWritable();
for (const className of classNames) {
this.__classes.delete(className);
}
return this;
}
getClasses(): Set<string> {
return this.getLatest().__classes;
}
}
Overrides

ElementNode.afterCloneFrom

collapseAtStart()

collapseAtStart(): true

Defined in: packages/lexical-rich-text/src/index.ts:460

Returns

true

Overrides

ElementNode.collapseAtStart

createDOM()

createDOM(config): HTMLElement

Defined in: packages/lexical-rich-text/src/index.ts:376

Called during the reconciliation process to determine which nodes to insert into the DOM for this Lexical Node.

This method must return exactly one HTMLElement. Nested elements are not supported.

Do not attempt to update the Lexical EditorState during this phase of the update lifecycle.

Parameters
config

EditorConfig

Returns

HTMLElement

Overrides

ElementNode.createDOM

exportDOM()

exportDOM(editor): DOMExportOutput

Defined in: packages/lexical-rich-text/src/index.ts:392

Controls how the this node is serialized to HTML. This is important for copy and paste between Lexical and non-Lexical editors, or Lexical editors with different namespaces, in which case the primary transfer format is HTML. It's also important if you're serializing to HTML for any other reason via $generateHtmlFromNodes. You could also use this method to build your own HTML renderer.

Parameters
editor

LexicalEditor

Returns

DOMExportOutput

Overrides

ElementNode.exportDOM

exportJSON()

exportJSON(): SerializedHeadingNode

Defined in: packages/lexical-rich-text/src/index.ts:422

Controls how the this node is serialized to JSON. This is important for copy and paste between Lexical editors sharing the same namespace. It's also important if you're serializing to JSON for persistent storage somewhere. See Serialization & Deserialization.

Returns

SerializedHeadingNode

Overrides

ElementNode.exportJSON

extractWithChild()

extractWithChild(): boolean

Defined in: packages/lexical-rich-text/src/index.ts:470

Returns

boolean

Overrides

ElementNode.extractWithChild

getTag()

getTag(): HeadingTagType

Defined in: packages/lexical-rich-text/src/index.ts:364

Returns

HeadingTagType

insertNewAfter()

insertNewAfter(selection?, restoreSelection?): HeadingNode | ParagraphNode

Defined in: packages/lexical-rich-text/src/index.ts:430

Parameters
selection?

RangeSelection

restoreSelection?

boolean = true

Returns

HeadingNode | ParagraphNode

Overrides

ElementNode.insertNewAfter

setTag()

setTag(tag): this

Defined in: packages/lexical-rich-text/src/index.ts:368

Parameters
tag

HeadingTagType

Returns

this

updateDOM()

updateDOM(prevNode, dom, config): boolean

Defined in: packages/lexical-rich-text/src/index.ts:388

Called when a node changes and should update the DOM in whatever way is necessary to make it align with any changes that might have happened during the update.

Returning "true" here will cause lexical to unmount and recreate the DOM node (by calling createDOM). You would need to do this if the element tag changes, for instance.

Parameters
prevNode

this

dom

HTMLElement

config

EditorConfig

Returns

boolean

Overrides

ElementNode.updateDOM

updateFromJSON()

updateFromJSON(serializedNode): this

Defined in: packages/lexical-rich-text/src/index.ts:416

Update this LexicalNode instance from serialized JSON. It's recommended to implement as much logic as possible in this method instead of the static importJSON method, so that the functionality can be inherited in subclasses.

The LexicalUpdateJSON utility type should be used to ignore any type, version, or children properties in the JSON so that the extended JSON from subclasses are acceptable parameters for the super call.

If overridden, this method must call super.

Parameters
serializedNode

LexicalUpdateJSON<SerializedHeadingNode>

Returns

this

Example
class MyTextNode extends TextNode {
// ...
static importJSON(serializedNode: SerializedMyTextNode): MyTextNode {
return $createMyTextNode()
.updateFromJSON(serializedNode);
}
updateFromJSON(
serializedNode: LexicalUpdateJSON<SerializedMyTextNode>,
): this {
return super.updateFromJSON(serializedNode)
.setMyProperty(serializedNode.myProperty);
}
}
Overrides

ElementNode.updateFromJSON


QuoteNode

Defined in: packages/lexical-rich-text/src/index.ts:180

Extends

Methods

$config()

$config(): BaseStaticNodeConfig & object & StaticNodeTypeAccessor<"quote"> & StaticNodeConfigAccessor<{ extends: typeof ElementNode; importDOM: { blockquote: () => object; }; stateConfigs: readonly [{ flat: true; stateConfig: StateConfig<"shadowRoot", boolean>; }]; }>

Defined in: packages/lexical-rich-text/src/index.ts:181

Override this to implement the new static node configuration protocol, this method is called directly on the prototype and must not depend on anything initialized in the constructor. Generally it should be a trivial implementation.

Returns

BaseStaticNodeConfig & object & StaticNodeTypeAccessor<"quote"> & StaticNodeConfigAccessor<{ extends: typeof ElementNode; importDOM: { blockquote: () => object; }; stateConfigs: readonly [{ flat: true; stateConfig: StateConfig<"shadowRoot", boolean>; }]; }>

Example
class MyNode extends TextNode {
$config() {
return this.config('my-node', {extends: TextNode});
}
}
Overrides

ElementNode.$config

canMergeWhenEmpty()

canMergeWhenEmpty(): true

Defined in: packages/lexical-rich-text/src/index.ts:286

Determines whether this node, when empty, can merge with a first block of nodes being inserted.

This method is specifically called in RangeSelection.insertNodes to determine merging behavior during nodes insertion.

Returns

true

Example
// In a ListItemNode or QuoteNode implementation:
canMergeWhenEmpty(): true {
return true;
}
Overrides

ElementNode.canMergeWhenEmpty

collapseAtStart()

collapseAtStart(): true

Defined in: packages/lexical-rich-text/src/index.ts:268

Returns

true

Overrides

ElementNode.collapseAtStart

createDOM()

createDOM(config): HTMLElement

Defined in: packages/lexical-rich-text/src/index.ts:217

Called during the reconciliation process to determine which nodes to insert into the DOM for this Lexical Node.

This method must return exactly one HTMLElement. Nested elements are not supported.

Do not attempt to update the Lexical EditorState during this phase of the update lifecycle.

Parameters
config

EditorConfig

Returns

HTMLElement

Overrides

ElementNode.createDOM

exportDOM()

exportDOM(editor): DOMExportOutput

Defined in: packages/lexical-rich-text/src/index.ts:226

Controls how the this node is serialized to HTML. This is important for copy and paste between Lexical and non-Lexical editors, or Lexical editors with different namespaces, in which case the primary transfer format is HTML. It's also important if you're serializing to HTML for any other reason via $generateHtmlFromNodes. You could also use this method to build your own HTML renderer.

Parameters
editor

LexicalEditor

Returns

DOMExportOutput

Overrides

ElementNode.exportDOM

exportJSON()

exportJSON(): SerializedQuoteNode

Defined in: packages/lexical-rich-text/src/index.ts:250

Controls how the this node is serialized to JSON. This is important for copy and paste between Lexical editors sharing the same namespace. It's also important if you're serializing to JSON for persistent storage somewhere. See Serialization & Deserialization.

Returns

SerializedQuoteNode

Overrides

ElementNode.exportJSON

insertNewAfter()

insertNewAfter(_, restoreSelection?): ParagraphNode

Defined in: packages/lexical-rich-text/src/index.ts:260

Parameters
_

RangeSelection

restoreSelection?

boolean

Returns

ParagraphNode

Overrides

ElementNode.insertNewAfter

isShadowRoot()

isShadowRoot(): boolean

Defined in: packages/lexical-rich-text/src/index.ts:200

true when this quote has opted in to shadow root behavior with setIsShadowRoot or $createQuoteNode({shadowRoot: true}), in which case it contains block-level children rather than inline content. false (the legacy inline-content behavior) by default.

Returns

boolean

Overrides

ElementNode.isShadowRoot

setIsShadowRoot()

setIsShadowRoot(isShadowRoot): this

Defined in: packages/lexical-rich-text/src/index.ts:211

Opt this quote in to (or out of) shadow root behavior. See quoteShadowRootState. Note that this does not restructure any existing children; a shadow root quote is expected to contain block-level children (non-element children will be normalized into paragraphs by the built-in shadow root transform).

Parameters
isShadowRoot

boolean

Returns

this

updateDOM()

updateDOM(prevNode, dom, config): boolean

Defined in: packages/lexical-rich-text/src/index.ts:222

Called when a node changes and should update the DOM in whatever way is necessary to make it align with any changes that might have happened during the update.

Returning "true" here will cause lexical to unmount and recreate the DOM node (by calling createDOM). You would need to do this if the element tag changes, for instance.

Parameters
prevNode

this

dom

HTMLElement

config

EditorConfig

Returns

boolean

Overrides

ElementNode.updateDOM

importJSON()

static importJSON(serializedNode): QuoteNode

Defined in: packages/lexical-rich-text/src/index.ts:254

Controls how the this node is deserialized from JSON. This is usually boilerplate, but provides an abstraction between the node implementation and serialized interface that can be important if you ever make breaking changes to a node schema (by adding or removing properties). See Serialization & Deserialization.

Parameters
serializedNode

SerializedQuoteNode

Returns

QuoteNode

Overrides

ElementNode.importJSON

Interfaces

HeadingAnnounceExtensionConfig

Defined in: packages/lexical-rich-text/src/HeadingAnnounceExtension.ts:15

Properties

created

created: string

Defined in: packages/lexical-rich-text/src/HeadingAnnounceExtension.ts:20

Announced when a block becomes a heading. %s is replaced with the level (1-6).

destroyed

destroyed: string

Defined in: packages/lexical-rich-text/src/HeadingAnnounceExtension.ts:25

Announced when a heading stops being a heading. %s is replaced with the level it was.

disabled

disabled: boolean

Defined in: packages/lexical-rich-text/src/HeadingAnnounceExtension.ts:30

When true, headings are not announced. Toggle at runtime via the output signal. Default false.


RichTextConfig

Defined in: packages/lexical-rich-text/src/LexicalRichTextExtension.ts:62

Configuration for RichTextExtension.

Properties

escapeFormatTriggers

escapeFormatTriggers: EscapeFormatTriggerConfig

Defined in: packages/lexical-rich-text/src/LexicalRichTextExtension.ts:63

Per-format trigger configuration that controls which text formats are automatically cleared from the selection on specific user interactions.

Defaults to:

{
capitalize: {enter: true, space: true, tab: true},
lowercase: {enter: true, space: true, tab: true},
uppercase: {enter: true, space: true, tab: true},
}

To opt in to escaping code formatting at text node boundaries:

configExtension(RichTextExtension, {
escapeFormatTriggers: {
code: {onlyAtBoundary: true, enter: true, click: true, arrow: true},
},
})
shouldHandlePasteAsFiles

shouldHandlePasteAsFiles: ShouldHandlePasteAsFiles

Defined in: packages/lexical-rich-text/src/LexicalRichTextExtension.ts:64

Type Aliases

EscapeFormatTrigger

EscapeFormatTrigger = "enter" | "click" | "arrow" | "space" | "tab"

Defined in: packages/lexical-rich-text/src/index.ts:619

Trigger types that cause format escape at text node boundaries.

  • enter: Escape on Enter key press
  • click: Escape on mouse click
  • arrow: Escape on arrow key navigation (left/right)
  • space: Escape on Space key press
  • tab: Escape on Tab key press

EscapeFormatTriggerConfig

EscapeFormatTriggerConfig = { [K in TextFormatType]?: TriggerConfig | null }

Defined in: packages/lexical-rich-text/src/index.ts:642

Per-format trigger configuration. Each TextFormatType maps to its own set of triggers, or null to explicitly disable escape for that format (useful when overriding defaults via configExtension).


HeadingTagType

HeadingTagType = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"

Defined in: packages/lexical-rich-text/src/index.ts:308


SerializedHeadingNode

SerializedHeadingNode = Spread<{ tag: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; }, SerializedElementNode>

Defined in: packages/lexical-rich-text/src/index.ts:144


SerializedQuoteNode

SerializedQuoteNode = Spread<{ shadowRoot?: boolean; }, SerializedElementNode>

Defined in: packages/lexical-rich-text/src/index.ts:154


ShouldHandlePasteAsFiles

ShouldHandlePasteAsFiles = (files, hasTextContent) => boolean

Defined in: packages/lexical-rich-text/src/index.ts:1187

Decides whether a paste event carrying files should be handled by dispatching DRAG_DROP_PASTE with those files, rather than falling through to the regular HTML paste handling.

Parameters

files

File[]

The files present on the clipboard, if any

hasTextContent

boolean

Whether the clipboard also carries text/html or text/plain content

Returns

boolean


TriggerConfig

TriggerConfig = { [K in EscapeFormatTrigger]?: boolean } & object

Defined in: packages/lexical-rich-text/src/index.ts:631

Trigger flags for a single format type. Set a trigger key to true to escape that format when the corresponding user interaction occurs.

When onlyAtBoundary is true, the format is only escaped when the cursor is at the start or end of a formatted text node with no adjacent sibling in that direction. When onlyAtBoundary is false or omitted the format is always escaped regardless of cursor position (matching the legacy $resetCapitalization behavior).

Type Declaration

onlyAtBoundary?

optional onlyAtBoundary?: boolean

Variables

DRAG_DROP_PASTE

const DRAG_DROP_PASTE: LexicalCommand<File[]>

Defined in: packages/lexical-rich-text/src/index.ts:151


HeadingAnnounceExtension

const HeadingAnnounceExtension: LexicalExtension<HeadingAnnounceExtensionConfig, "@lexical/rich-text/HeadingAnnounce", NamedSignalsOutput<HeadingAnnounceExtensionConfig>, unknown>

Defined in: packages/lexical-rich-text/src/HeadingAnnounceExtension.ts:55

Announces headings through the AriaLiveRegionExtension sink: a block becoming a heading, and a heading ceasing to be one.

The markdown shortcut consumes both keystrokes (# then space) and swaps the block type, which is silent to a screen reader — so without this the user has no way to know the transformation happened, or to confirm the level without navigating out of the block and back in.

Only those two transitions announce. Typing inside a heading, moving the caret through it, and deleting text while the heading survives are all silent; announcing on every keystroke would make a heading impossible to type into.

A destroyed node is gone from the current editor state, so its level is read from the previous state registerMutationListener provides.


quoteShadowRootState

const quoteShadowRootState: StateConfig<"shadowRoot", boolean>

Defined in: packages/lexical-rich-text/src/index.ts:175

Opt-in state for QuoteNode.isShadowRoot. When true, the quote behaves like a multi-block region (similar to a table cell): it holds block-level children (paragraphs, headings, ...) instead of inline content, which allows more faithful HTML and Markdown import/export of <blockquote> content. Defaults to false, in which case there is no change to the legacy behavior (and nothing extra is serialized).


RichTextExtension

const RichTextExtension: LexicalExtension<RichTextConfig, "@lexical/rich-text", NamedSignalsOutput<RichTextConfig>, unknown>

Defined in: packages/lexical-rich-text/src/LexicalRichTextExtension.ts:111


RichTextImportExtension

const RichTextImportExtension: LexicalExtension<ExtensionConfigBase, "@lexical/rich-text/Import", unknown, unknown>

Defined in: packages/lexical-rich-text/src/LexicalRichTextExtension.ts:152

Experimental

Bundles RichTextImportRules together with the runtime RichTextExtension.

Deprecated

RichTextExtension now registers RichTextImportRules (and CoreImportExtension) itself — depend on it directly instead.


RichTextImportRules

const RichTextImportRules: DOMImportRule<ElementSelectorBuilder<HTMLSpanElement, Record<string, never>>>[]

Defined in: packages/lexical-rich-text/src/RichTextImportExtension.ts:135

Experimental

Import rules for HeadingNode and QuoteNode, including the Google Docs title heuristic that the legacy HeadingNode.importDOM declared. The Google-Docs rules are registered last (highest priority) so they precede the generic <p> and <span> rules from CoreImportRules.

Registered by RichTextExtension itself (together with CoreImportExtension), so any editor that uses the rich-text extension can import these tags through the DOMImportExtension pipeline without further configuration.


ShadowRootQuoteRule

const ShadowRootQuoteRule: DOMImportRule<ElementSelectorBuilder<HTMLQuoteElement, Record<string, never>>>

Defined in: packages/lexical-rich-text/src/RichTextImportExtension.ts:81

Experimental

Opt-in replacement for the default <blockquote> rule that imports the quote as a shadow root QuoteNode (see quoteShadowRootState). Block-level children such as <p> are preserved as blocks and runs of inline content are wrapped in paragraphs (BlockSchema), so structured blockquote HTML round-trips faithfully instead of being flattened to inline content.

Not part of RichTextImportRules; without it <blockquote> import behavior is unchanged. To opt in, register it with a higher priority than the default rules, e.g.:

configExtension(DOMImportExtension, {rules: [ShadowRootQuoteRule]})

(rules from later configuration take priority, so this shadows the default @lexical/rich-text/blockquote rule).

Functions

$createHeadingNode()

$createHeadingNode(headingTag?): HeadingNode

Defined in: packages/lexical-rich-text/src/index.ts:509

Parameters

headingTag?

HeadingTagType = 'h1'

Returns

HeadingNode


$createQuoteNode()

$createQuoteNode(options?): QuoteNode

Defined in: packages/lexical-rich-text/src/index.ts:291

Parameters

options?
shadowRoot?

boolean

When true the quote opts in to shadow root behavior (see quoteShadowRootState). Defaults to false.

Returns

QuoteNode


$isHeadingNode()

$isHeadingNode(node): node is HeadingNode

Defined in: packages/lexical-rich-text/src/index.ts:515

Parameters

node

LexicalNode | null | undefined

Returns

node is HeadingNode


$isQuoteNode()

$isQuoteNode(node): node is QuoteNode

Defined in: packages/lexical-rich-text/src/index.ts:302

Parameters

node

LexicalNode | null | undefined

Returns

node is QuoteNode


defaultShouldHandlePasteAsFiles()

defaultShouldHandlePasteAsFiles(files, hasTextContent): boolean

Defined in: packages/lexical-rich-text/src/index.ts:1198

The historical behavior: files are only handled when the clipboard carries no text content at all. Note that browsers put a text/html fallback on the clipboard alongside the file when an image is copied via the context menu, so this default routes such images through the HTML importer.

Parameters

files

File[]

hasTextContent

boolean

Returns

boolean


registerRichText()

registerRichText(editor, escapeFormatTriggers?, shouldHandlePasteAsFiles?): () => void

Defined in: packages/lexical-rich-text/src/index.ts:1205

Parameters

editor

LexicalEditor

escapeFormatTriggers?

ReadonlySignal<EscapeFormatTriggerConfig> = ...

shouldHandlePasteAsFiles?

ReadonlySignal<ShouldHandlePasteAsFiles> = ...

Returns

() => void

References

eventFiles

Re-exports eventFiles