Open LogicLaneTech opened 1 year ago
Place the table inside the collapsible content, is that what you are looking for? @TheDivineCodes
Nice, so you need to wrap each row inside the collapsible trigger and put the content inside the collapsible content Something like this:
<table>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
<tr>
<Collapsible>
<CollapsibleTrigger>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</CollapsibleTrigger>
<CollapsibleContent>
Row collapsible content
</CollapsibleContent>
</Collapsible>
</tr>
</table>
For using that collapsible tag do I need to import something?
Yes you have to add the component file as it says in the documentation, I recommend you use the cli tool and install only the components you need, in this case the collapsible, look at this
After installing it :
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible"
Okay after rendering this is not giving me the same result as the one above
Could you replicate it in codesandbox to try to review it? Thank you
I used shadcn/ui to build a collapsible table. I stumbled on this issue before I built it and realized that except this issue and a bunch of references to tanstack/table, there is not good resource how to build it.
So I made a quick tutorial for those of you interested.
I was trying to solve it with the Accordion
component until I saw this and @jocarrd mentioning Collapsible
.
I hope this helps anyone else coming to this issue by searching on google (like I and most of you did). Feedback is always welcome :)
https://dev.to/mfts/build-an-expandable-data-table-with-2-shadcnui-components-4nge
I was trying to solve it with the
Accordion
component until I saw this and @jocarrd mentioningCollapsible
.
Nice article. Why not just use the Expanding
API from tanstack? The collapsible doesn't have an animation or anything unique, so just using the inbuilt tanstack one gives more functionality imo.
Edit: Was late when I sent this. Just realized that the article doesn't even use tanstack lol. So collapsible is a good solution for that.
If you do use tanstack to create the advanced data table, look into the expandable feature from tanstack.
Just realized that the article doesn't even use tanstack lol. So collapsible is a good solution for that.
Yes I didn't use tanstack because it felt an overkill for what I need the table for.
I used shadcn/ui to build a collapsible table. I stumbled on this issue before I built it and realized that except this issue and a bunch of references to tanstack/table, there is not good resource how to build it.
So I made a quick tutorial for those of you interested.
I was trying to solve it with the
Accordion
component until I saw this and @jocarrd mentioningCollapsible
.I hope this helps anyone else coming to this issue by searching on google (like I and most of you did). Feedback is always welcome :)
https://dev.to/mfts/build-an-expandable-data-table-with-2-shadcnui-components-4nge
Thanks for the nice setup. Unfortunatly, I have the following error "Error: React.Children.only expected to receive a single React element child.". It seems to be related to TableRow & CollapsibleContent at the same level... when I remove CollapsibleContent, the error disapear :/ Did you have the same?
I used shadcn/ui to build a collapsible table. I stumbled on this issue before I built it and realized that except this issue and a bunch of references to tanstack/table, there is not good resource how to build it. So I made a quick tutorial for those of you interested. I was trying to solve it with the
Accordion
component until I saw this and @jocarrd mentioningCollapsible
. I hope this helps anyone else coming to this issue by searching on google (like I and most of you did). Feedback is always welcome :) https://dev.to/mfts/build-an-expandable-data-table-with-2-shadcnui-components-4ngeThanks for the nice setup. Unfortunatly, I have the following error "Error: React.Children.only expected to receive a single React element child.". It seems to be related to TableRow & CollapsibleContent at the same level... when I remove CollapsibleContent, the error disapear :/ Did you have the same?
After few extra investigation, it seems connected to this problem : https://github.com/radix-ui/primitives/issues/1979
Error: React.Children.only expected to receive a single React element child
@laurent512 if you use asCild
then just wrap everything inside it into a fragment <></>
and it interprets the code as a single react element.
Error: React.Children.only expected to receive a single React element child
@laurent512 if you use
asCild
then just wrap everything inside it into a fragment<></>
and it interprets the code as a single react element.
Thanks for your article. I have everything wrapped in a fragment like you mentioned but it's still throwing the same error Error: React.Children.only expected to receive a single React element child.
.
Any advice?
This is my current code:
{/* ... */}
<TableBody>
{categories.map((c: Category) => (
<Collapsible key={c.id} asChild>
<>
<CategoryRow
category={c}
categoryTypes={categoryTypes}
subCategoriesCell={
<CollapsibleTrigger asChild>
<>{c.subCategories.length}</>
</CollapsibleTrigger>
}
/>
<CollapsibleContent asChild>
<SubCategoryRows subCategories={c.subCategories} />
</CollapsibleContent>
</>
</Collapsible>
))}
</TableBody>
{/* ... */}
Hmmm that's super strange. I cannot spot any irregularities.
One thing you can try to change is this line:
Before:
<CollapsibleTrigger asChild>
<>{c.subCategories.length}</>
</CollapsibleTrigger>
After:
<CollapsibleTrigger>
{c.subCategories.length}
</CollapsibleTrigger>
Hmmm that's super strange. I cannot spot any irregularities.
One thing you can try to change is this line:
Before:
<CollapsibleTrigger asChild> <>{c.subCategories.length}</> </CollapsibleTrigger>
After:
<CollapsibleTrigger> {c.subCategories.length} </CollapsibleTrigger>
Same result unfortunately :(
Hmmm that's super strange. I cannot spot any irregularities.
One thing you can try to change is this line:
Before:
<CollapsibleTrigger asChild> <>{c.subCategories.length}</> </CollapsibleTrigger>
After:
<CollapsibleTrigger> {c.subCategories.length} </CollapsibleTrigger>
@akyrey I found the solution. The issue is not that part of the code. The issue is the fragment that is supposed to be used in the 'Collapsible' area. This will occur while using SSR (tested with nextjs 14). It seems as if fragments do not work with SSR in the same way you may expect them to...this may be a bug? The solution is to have the "use client" text at the top of your file to make it a client component (I would break out that part of the code into a separate file). I opened a bug to the NextJs team as well
To update this thread again, if you would like to use this functionality in a server component, you can! As it turns out react has an optimization on the server side that basically gets rid of all keyless fragments. Give your fragment a key and you should be good to go :)
Any help with using the Accordion instead the Collapsible?
I had a same request as well, main request was to click a campaign and a subtable would expand.
First approach was:
<CollapsibleContent asChild>
{openRows[row.id] && (
<tr className="p-4">
<SubTable data={geoData} />
</tr>
)}
</CollapsibleContent>
And then inside the
Second Approach was :
Used Table component directly inside
<td colSpan={15} className="rounded-md border z-99">
<Table className="static h-auto">
..
</Table>
</td>
Did anyone find a solution for this, im stuggleing to make it work. Also @mfts i couldent find source code for you guide on the expandable rows. I have a issue that the expandable row is not full-width.
This works for me
first, if you are working with nextJS the component needs to be a client component
"use client";
second, you have to make a little change in the ui/table.tsx (add a type="" attr)
// the empty type attribute is a workaround for a problem with radix dialog on tables
const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className
)}
{...props}
// @ts-ignore
type=""
/>
));
TableRow.displayName = "TableRow";
third, you need write something like this:
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice, i) => (
<Collapsible asChild>
<>
<CollapsibleTrigger asChild>
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">
{invoice.invoice}
</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">
{invoice.totalAmount}
</TableCell>
</TableRow>
</CollapsibleTrigger>
<CollapsibleContent asChild>
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">----</TableCell>
<TableCell>----</TableCell>
<TableCell>----</TableCell>
<TableCell className="text-right">----</TableCell>
</TableRow>
</CollapsibleContent>
</>
</Collapsible>
))}
</TableBody>
</Table>
I also did some quick tests with the Accordion component but I couldn't get it to work as it should due to lack of time.
Since I found this several times, trying to find a way to simply add an expandable section with just shadcn. I'll add the solution I'm happy with. I recommend following the shadcn example, you dont need everything, but you do need the row selection portion. With that added in, swap out TableBody with this. Most important thing with this, was discovering the colSpan, that solved all my issues, as before all my attempts resulted in the expandable only being in the first column.
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => {
return (
<>
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow >
{row.getIsSelected() && (
<TableRow>
<TableCell colSpan={row.getVisibleCells().length}>
<div className="w-full h-64">
<h1>Content Hereeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee</h1>
</div>
</TableCell>
</TableRow>
)}
</>
)
})
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
Anyone able to get it to work with Accordion
? I keep getting Error: React.Children.only expected to receive a single React element child.
despite adding use client
and Fragment
s with key
s as the child of each accordion element with asChild
.
How can I create collapsible tables with this?