[BUG] TableVirtuoso EmptyPlaceholder is rendered inside the table without proper wrapper elements
See original GitHub issueDescribe the bug
When setting EmptyPlaceholder to a custom component, it is rendered inside the <table> element. This is wrong for two reasons:
- Semantically, I believe this is incorrect. One could wrap the contents of the actual placeholder inside
<tbody><tr><td>, but it should not be part of the table. For example, when a screen reader user would go to read the table, they would be told that the table has a row of data, while actually it does not. - If you believe the above behavior is correct, i.e. that EmptyPlaceholder should render in Having to wrap the EmptyPlaceholder with multiple additional components seems overly complex to use. I would much rather have the placeholder be just another div below the table. Rendering with a div currently creates invalid HTML, which React tells to developers.
Reproduction https://codesandbox.io/s/sandpack-project-forked-yw9tr6
To Reproduce Steps to reproduce the behavior:
- Go to the CodeSandbox
- Open the internal browser console.
- See DOM nesting validation error
Expected behavior
I would expect either:
- That the EmptyPlaceholder would be rendered outside the
<table>HTML element, removing the need to wrap it with multiple HTML elements, and making the DOM validation error disappear. This could however be considered sort of a breaking change, i.e. if someone is currently adding the additional table elements in EmptyPlaceholder, this would cause their HTML structure to break. - That TableVirtuoso would wrap EmptyPlaceholder in
<tbody><tr><td>itself. This might be hard because I think TableVirtuoso does not know currently how many columns there are, so can’t set colSpan correctly, but would otherwise make using the component easier.
Desktop (please complete the following information):
- OS: Windows 11.
- Browser: Edge 103
Additional context I can probably make some time to fix this, if we settle on a solution.
Issue Analytics
- State:
- Created a year ago
- Comments:8 (8 by maintainers)
Top Results From Across the Web
Interface: TableComponents<Context> - React Virtuoso
Defined in src/interfaces.ts:177. Set to render a custom UI ... Set to render an empty item placeholder. ... Set to customize the wrapping...
Read more >Empty or Missing Table Header - Equalize Digital
A table header is a row at the top or on the side of a table that is used to describe either individual...
Read more ><div> cannot appear as a child of <table> - You.com - You.com
Most likely the component Spinner renders a <div> as the outermost node. Check the implementation of it. You implicitly render it inside <tbody>...
Read more >HISTORY.md · master · RocketChat / Rocket.Chat · GitLab
Sort RecordList items in REVERSE chronological order, not FORWARD (#27201 by ... Restore current chats default table order (#26808). Sign in ...
Read more >Firefox doesn't style :empty elements - Stack Overflow
Firefox has incompatibility with td:empty not because there is an issue with ... table input { border: none; } [placeholder] { color: gray; ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

That’s at least partially because the table does not have fixed layout and the columns don’t have explicit widths either, right? I think those are mostly mandatory anyway, to keep the table layout from shifting around when rows with different content lengths are added/removed by Virtuoso.
I update the sandbox to include those styles, this way the thead will keep the same layout not depending on data count: https://codesandbox.io/s/sandpack-project-forked-yw9tr6?file=/App.js
But just to reiterate, my main issue with the current solution is still that the placeholder renders a row in the body, which gives false info to assistive tech. Given that table structures are quite strict, I don’t think there’s any special role that row could be given to work around this.
Certainly food for thought here. If the table is empty, I would probably expect that its columns are still visible, and there’s an “no data” message rendered within the table. That was my assumption when doing the placeholder the way it is now. Rendering a placeholder outside of the table will leave the table collapsed, which I feel to be suboptimal if it has some sort of a border. And yes, pre-wrapping the placeholder in tbody/tr/td is not possible because of unknown td counts.