docs/solutions/logic-errors/2026-05-09-html-div-boundaries-must-survive-inline-wrappers.md
Lexical's core HTMLCopyAndPaste.test.ts treats generic <div> as a visible
block boundary, even when it is nested under a <span> or another <div>.
Slate v2's paste-html importer treated unknown elements as transparent
children, so 123<div>456</div> and <span>123<div>456</div></span> collapsed
into one paragraph.
['123', '456'] but received ['123456'].['a b c d e', 'f g h'] but received one
flattened paragraph.Deserialize generic DIV nodes as body-like fragments:
if (nodeName === 'DIV') {
return jsx('fragment', {}, normalizeBodyFragment(children))
}
Then protect list-item handling from wrapping an already block-shaped DIV
fragment in another paragraph:
if (meaningfulValues.length > 0 && meaningfulValues.every(isTopLevelBlock)) {
return meaningfulValues
}
DIV is not just a style wrapper in copied editor HTML. It often carries the
same visible boundary as a paragraph. Treating it like a body fragment lets
inline children flush into paragraphs while preserving nested block children.
The list guard keeps existing list boundary rows honest: a div inside an li
can still become a paragraph boundary, but already block-shaped children are
not nested under a second paragraph.
paste-html-import.ts, run the focused Lexical core rows and
the full paste-html.test.ts browser file.