svelte
svelte copied to clipboard
Svelte 5 : <tr> is invalid inside <table>
Describe the bug
The following markup throws an exception
<table><tr></tr></table>
````
### Reproduction
https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAE6tWSsvMSS1WsoquVspLzE1VslJyLChQ0lEqqSwAcYrLUnNKUoH84vzSomSQiE1JYlJOqp1NSZGdjT6EAAsA1eTmp2SmZaamKFmVFJWm1sbWAgBDd7JdXgAAAA==
### Logs
_No response_
### System Info
```shell
Svelte 5
Severity
annoyance
The check is happening here.
https://github.com/sveltejs/svelte/blob/cb529fc666a3fb5fd35b27b91c61494a615a8106/packages/svelte/src/compiler/phases/2-analyze/validation.js#L231-L255
It says in the spec that tr
is a valid tag, along with td
and th
. But a tbody
should be inserted as a parent tag automatically.
So, is svelte trying to enforce the manual addition of tbody
?
I can make the PR to allow tr
, td
and th
if that's a valid case.
There is a problem here with hydration. If the SSR generates a table that looks different than the DOM that browser creates via the normalization (e.g. adding a missing tbody
), the mismatch can cause the hydration to fail.
The issue was already known, would recommend waiting for maintainer feedback on this.
I don't think Svelte should add the missing tbody
here. That would be very confusing to have the framework adding tags not present in the source. Since browsers are accepting a <tr>
directly inside a <table>
svelte should leave the markup unchanged as does Svelte 4 and other UI frameworks.
This is the result of the limitation of the new way of component rendering - creating all the elements in one go and extracting references to the elements. But when a browser corrects the template structure, it breaks the reference extraction.
Maybe the compiler can just do all the structure correction under the hood. However, it can lead to a confusing experience when a CSS rule doesn't apply to an element or apply to another element because the DOM structure in the source and in the browser differs. So it makes sense to write a markup that will not change its structure.
On MDN <tbody>
are omitted in some of the examples https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table#simple_table, so I think it is a reasonable way to write the markup for a table, and Svelte rejecting it as invalid is unexpected.
Although if this is an unavoidable technical limitation of the new rendering model that should be explicitly documented, especially in the migration guide.
From @trueadm on an earlier discussion we had about this:
The browser always inserts a <tbody>
when you don't put one in. We need to have a <tbody>
then to avoid breaking our template mechanic in Svelte 5. There's not a super simple solution here. We either have to try and detect this at runtime or we try and do it statically between modules somehow, but both are pretty difficult. Solid, etc. have the same error. They push for the developer to fix their code and they class this as invalid, as does React.
One possible way would be when we append templates, we can see what the nodes are that we append and check if the parent we're appending to is a <table>
and appropriately add a tbody
element, and vice versa for when we traverse the elements. This will incur a small overhead cost for checking though, so maybe we can somehow get the compiler to give us a good estimate by looking at the template to see if we're dealing with <tr>
elements.
In my case, <tbody>
is there, but <tr>
are inside a {#if}{/if}
section, the error is raised.
Reproduction
https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAE31R3UrFMAx-lVIFz0FhTu9mN_A5nBdbl2GxS-eaCofSd7fr_gTl3CXfX9LU815psLx48xybAXjBX8eRP3C6jHNjv0ETxN4aN8kZEVZOaqSqxpo0EJPGIbGS3VpqCE6P55fIRK53KEkZZArlBAMgnc7Mz0xNi-e-ZPksplCjyI5YFK0jik6DUiv5Wfo9IqSxCbUF8yknuRfH4qam1ZCEgj6g6aplqKBprRJREVhiuchi-Qd--h9-_gXHcsmbsW2KoNZ0l1Xhb1S_nSc-NRxxxyLbLeDLNdqyfNdku8gXoC1cdXcG765nZKoP67LrhrFKd4p_O5hO9Qo6XtDkILyHHzQhkBkWAgAA
@R3D2 you forgot about <td>
/<th>
. You cannot add text right to <tr>
.