Skip to main content

Document Model

An editor state holds a tree of nodes. This page explains how that tree is shaped.

A DOM-like tree​

Lexical's node tree is shaped like the HTML it renders. A paragraph is an ElementNode whose children are the nodes inside it, and inline structure nests the same way: a link is a LinkNode element that contains the text nodes it wraps, just as an <a> contains its text. Each node type decides how it renders with createDOM() and updateDOM(), so the model maps closely to the DOM, and a position in the document is a node plus an offset within it.

Here is a small document with a heading, a paragraph containing bold text and a link, a block image, and a card that has a named title slot as well as ordinary body children:

Solid arrows are ordinary children, which form an ordered list under their parent and are read with getChildren(). The dashed arrow is a named slot: a separate channel on the host, keyed by name instead of position and read with $getSlot(card, 'title'). A slot's value is the root of its own isolated region, so its getParent() is null and $getSlotHost() leads back to the card. Any ElementNode or DecoratorNode can host slots, so a decorator such as the image could also expose an editable caption this way.

Working with the tree​

Lexical code navigates the document the way DOM code does, with methods like getParent(), getChildren(), and getNextSibling(), and each node owns the DOM it renders. The resemblance is structural, not one node per HTML element: bold or italic text, for example, is a format on a TextNode, not a separate <strong> or <em> node. See Nodes for the built-in node types.

Customizing rendering​

You can also change how nodes render without subclassing them. DOMRenderExtension from @lexical/html takes overrides for createDOM, updateDOM, and exportDOM, for one node class or for every node, such as adding a data- attribute or wrapping a node's children in another element. Each override calls $next() to get the default result and adjusts it, so overrides from several extensions compose. Export overrides only affect HTML export, and createDOM overrides also carry through to export for nodes that use the default exportDOM. Changes made while updating the editor's DOM don't; see Lexical -> HTML for which hooks reach export.

For how the tree is converted to and from JSON, HTML, and Markdown, see Serialization. For how this model differs from a mark-based editor, see Compared with ProseMirror.