Back to Plate

Lexical paragraph node harvest rows need DOM import splitting

docs/solutions/best-practices/2026-05-09-lexical-paragraph-node-harvest-rows-need-dom-import-splitting.md

53.0.62.2 KB
Original Source

Lexical paragraph node harvest rows need DOM import splitting

Problem

Lexical ParagraphNode tests look like a paragraph behavior bundle, but most rows are Lexical class shape: constructor rules, JSON schema, DOM class output, factory helpers, and type guards. The portable row is narrower: paragraph DOM import should preserve valid alignment from CSS text-align and legacy align, with CSS winning when both are present.

Symptoms

  • Slate already had paragraph/block split and merge coverage.
  • The paste-html importer created paragraph elements but ignored paragraph alignment.
  • The paste-html renderer had align in the example value type but did not render it.
  • A browser test that counted every <p> was too brittle because the editor can retain an empty paragraph around pasted content.

Solution

Split the source file before porting:

  • reject constructor, schema, createDOM, updateDOM, factory, and type-guard rows as Lexical API shape;
  • route insert-after/split behavior through existing Slate insert-break and transform contracts;
  • port paragraph DOM import alignment as a focused paste-html browser row.

The browser proof should assert the imported paragraphs by text and then inspect their inline style.textAlign, not every rendered paragraph in the editor.

Why This Works

Slate owns paragraph alignment as editor data and rendering policy. The copied behavior is not Lexical's ParagraphNode class; it is the user-visible result of pasting standard paragraph HTML. Keeping the proof at the paste-html boundary protects the actual behavior without baking in Lexical internals.

Prevention

  • For upstream node tests, reject class/schema/helper rows unless Slate exposes the same public API.
  • Preserve CSS-over-attribute precedence when importing common HTML attributes.
  • In browser tests after paste, assert the imported blocks by content instead of assuming the exact editor wrapper count.