Personally, after reading up on it, I’d say like @asawyer
I see that both are valid HTML, the output is a little different though. If it breaks some of the output, a quick fix to mimic previous behavior would be:
li > p {
margin: 0;
display: inline;
}
Also, I do understand that if you’re upgrading it will be a while before you discover this new behavior. An editor makes a list and suddenly it looks different from all the other lists they made before.
We could change the defaults, but this has one very unfortunate side-effect: you’d never be able to use <p> elements in lists again (they would just be stripped). But that is valid HTML and has legitimate use cases. Using <p> inside <li> was also something you could already achieve in TinyMCE, so it would break things in different interesting ways which we’d need to find weird workarounds for ![]()
Just for perspective, this is what two LLMs that I consulted had to say about it:
TipTap uses ProseMirror’s schema. ProseMirror intentionally encourages:
<li> <p>…</p> </li>because:
- a block-level node (like
<p>) makes editing consistent- it avoids weird cursor behaviour
- it allows adding multiple paragraphs inside one list item
- it matches the HTML spec perfectly
- TinyMCE doesn’t do this by default because it’s older and tries to emulate “Word-like” content, not necessarily semantic correctness.
So is
<p>inside<li>more correct?
Yes. It is more semantically flexible and 100% valid HTML.Plain text directly inside
<li>is also valid, but wrapping content in a<p>:
- better reflects that it’s a block of text
- allows structured content inside a list item
- aligns with modern editors
- avoids ambiguous whitespace rules
This is why modern editors (TipTap, ProseMirror, CKEditor 5) use
<p>inside<li>.