solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
32.09k stars 914 forks source link

Nested `<p>` tags break render #1473

Closed spiffytech closed 1 year ago

spiffytech commented 1 year ago

Describe the bug

If my Solid template contains nested <p> tags, content won't be rendered:

import { render } from "solid-js/web";

function Hello() {
  return (
    <div>
      <p>This should say 'hello':</p>
      <p>
        <p>Hello</p>
      </p>
    </div>
  );
}

render(() => <Hello />, document.getElementById("app")!);

In a sandbox this produces an empty render. In Solid Start it produces a console error, Uncaught The browser resolved template HTML does not match JSX input.

Your Example Website or App

https://playground.solidjs.com/anonymous/39f50ef5-3851-4d0c-b04d-ff9fce0ab86a

Steps to Reproduce the Bug or Issue

Put a <p> inside another <p>.

Expected behavior

It renders. Or at least doesn't crash.

Screenshots or Videos

No response

Platform

Additional context

Technically trying this is in violation of the HTML spec, which says paragraphs may only contain "phrasing content", but <p> is flow content.

However, browsers support it regardless, and I've never seen anything barf on it so I'm surprised Solid does.

Normally I wouldn't write HTML like this. I just stumbled on it while experimenting with Solid Start and it took me a while to diagnose why my renders broke.

ryansolid commented 1 year ago

Solid doesn't do anything special here. Just generates the strings. What I expect is that the client is erroring out but the playground is squashing it for some reason(@modderme123). This might be worth looking into but we do a template check on startup that throws if the templates we generate don't match the browser which is the error you see in SolidStart. The reason we through is this is pretty much unrecoverable and by throwing we at least know what causes it. Whereas the errors you'd get otherwise would be really obscure.

Some more details that might help because sometimes we don't detect these issues during SSR. First browser only corrects at parsing time. Solid (and libraries like Lit) create nodes from parsing HTML strings and cloning them. This is different from VDOM libraries (and Svelte) which create them one by one. It has much better performance but your HTML needs to be well formed within a template. You can technically through inserting do something illegal and the browser won't correct it.

However for SSR where the finally output is a string the browser will correct even across template boundaries. This is much more difficult for us to account for. It can't be detected at compile time and especially with things like streaming where parts may be delivered at different times. Luckily this isn't your case and it is just a matter of the browser "fixing" stuff for us. There is an open issue in DOM Expressions tracking improvements here to detection. But it won't be fullproof I think: https://github.com/ryansolid/dom-expressions/issues/105

spiffytech commented 1 year ago

Ahhh, I see.

If I open DevTools and run

temp1.innerHTML = `<p><p>Hello</p></p>`

I get this even more malformed DOM:

<div>
  <p></p>
  <p>Hello</p>
  <p></p>
</div>

Whereas temp1.appendChild(...) created what I expected.

If Solid is handing the browser HTML strings under the hood, then this behavior / "limitation" makes sense, and I'll close in favor of https://github.com/ryansolid/dom-expressions/issues/105

Thanks!