Ramonda

RMD028 — An element the HTML parser is not allowed to keep here

<p>
  intro
  <div>a block</div>   {/* reported */}
</p>

The client builds the DOM with appendChild, which puts a node exactly where it is told. A parser does not:

your markup:    <p>intro<div>a block</div></p>
what a browser
builds from it: <p>intro</p><div>a block</div>

The <p> is closed early and the <div> becomes its sibling. So this works perfectly until the page is server-rendered, and then the DOM the browser built is not the tree render() described.

Without this, what you would see at that point is RMD007 — a mismatch — whose advice is about new Date() and typeof window. Neither is the problem: the server sent the right markup and the parser moved it.

What is reported, and what the parser does with each:

markupwhat happens
a block element inside <p>the <p> is closed; the block becomes its sibling
<li> outside <ul> / <ol> / <menu>relocated
<tr> outside a table, <td> outside a <tr>relocated
<option> outside <select> / <optgroup> / <datalist>relocated
<form> inside <form>the inner one is dropped; its fields join the outer form
<a> inside <a>the outer link is closed where the inner one starts

"A block element" is every tag that closes a <p> by the parser's own rule — div, ul, ol, table, h1h6, blockquote, form, hr, section, article, pre, figure, and the rest of flow content. Inline content — <strong>, <em>, <a>, <span> — is fine inside a <p>, which is what a <p> is for.

Put the element where the parser allows it. A block beside the paragraph rather than inside it, list items in a list, rows in a table. A component in between is invisible to this: what it renders is what the parser sees, so the pair reported is the real parent and the real child however many components sit between them in your JSX.

Next