Replies: 4 comments 7 replies
-
@LoicUV Thanks for the good idea via meta! I experimented a bit based on your solution and got it to work automatically, but didn't test on large nesting: <thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
const columnRelativeDepth = header.depth - header.column.depth;
if (
!header.isPlaceholder &&
columnRelativeDepth > 1 &&
header.id === header.column.id
) {
return null;
}
let rowSpan = 1;
if (header.isPlaceholder) {
const leafs = header.getLeafHeaders();
rowSpan = leafs[leafs.length - 1].depth - header.depth;
}
return (
<th
key={header.id}
colSpan={header.colSpan}
rowSpan={rowSpan}
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</th>
);
})}
</tr>
))}
</thead> My logic is that columns have the smallest depth, relative to the nested columns. And if the column depth is more than 1 greater than the column depth, it means that there is a placeholder and we don't display this header. The P.S. I couldn't figure out how to use the built-in rowSpan either. Do you have any new information about it? |
Beta Was this translation helpful? Give feedback.
-
@Hristy-A thanks! I use the following code to implement this interesting feature in vue import { FlexRender } from "@tanstack/vue-table";
export const Thead = ({ table }) => {
return <thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
const columnRelativeDepth = header.depth - header.column.depth;
if (
columnRelativeDepth > 1
) {
return null;
}
let rowSpan = 1;
if (header.isPlaceholder) {
const leafs = header.getLeafHeaders();
rowSpan = leafs[leafs.length - 1].depth - header.depth;
}
return (
<th
data-columnRelativeDepth={columnRelativeDepth}
key={header.id}
colspan={header.colSpan}
rowspan={rowSpan}
>
<FlexRender
render={header.column.columnDef.header}
props={header.getContext()}
/>
</th>
);
})}
</tr>
))}
</thead>
} |
Beta Was this translation helpful? Give feedback.
-
hello. import * as React from "react";
import ReactDOM from "react-dom/client";
import {
ColumnDef,
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";
declare module "@tanstack/table-core" {
// @ts-expect-error
interface ColumnMeta<TData extends RowData, TValue> {
rowSpan?: number;
}
}
type Person = {
test?: string,
firstName: string;
lastName: string;
age: number;
visits: number;
status: string;
progress: number;
};
const defaultData: Person[] = [
{
test: "aaa",
firstName: "tanner",
lastName: "linsley",
age: 24,
visits: 100,
status: "In Relationship",
progress: 50,
},
{
test: "bbb",
firstName: "tandy",
lastName: "miller",
age: 40,
visits: 40,
status: "Single",
progress: 80,
},
{
test: "ccc",
firstName: "joe",
lastName: "dirte",
age: 45,
visits: 20,
status: "Complicated",
progress: 10,
},
];
const columnHelper = createColumnHelper<Person>();
const columns = [
columnHelper.accessor("test", {
cell: (info) => info.getValue(),
meta: {
rowSpan: 3,
},
}),
columnHelper.group({
id: "hello",
header: () => <span>Hello</span>,
columns: [
columnHelper.accessor("firstName", {
cell: (info) => info.getValue(),
meta: {
rowSpan: 2,
},
}),
columnHelper.accessor((row) => row.lastName, {
id: "lastName",
cell: (info) => info.getValue(),
header: () => <span>Last Name</span>,
meta: {
rowSpan: 2,
},
}),
],
}),
columnHelper.group({
header: "Info",
columns: [
columnHelper.accessor("age", {
header: () => "Age",
meta: {
rowSpan: 2,
},
}),
columnHelper.group({
header: "More Info",
columns: [
columnHelper.accessor("visits", {
header: () => <span>Visits</span>,
}),
columnHelper.accessor("status", {
header: "Status",
}),
columnHelper.accessor("progress", {
header: "Profile Progress",
}),
],
}),
],
}),
];
export default function FlexibleHeaderTable() {
const [data, setData] = React.useState(() => [...defaultData]);
const rerender = React.useReducer(() => ({}), {})[1];
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<div className="p-2">
<table style={{ borderCollapse: 'collapse', width: '100%', border: '1px solid #e5e7eb' }}>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id} >
{headerGroup.headers.map((header) => {
const columnRelativeDepth = header.depth - header.column.depth;
if (
columnRelativeDepth > 1
) {
return null;
}
let rowSpan = 1;
if (header.isPlaceholder) {
const leafs = header.getLeafHeaders();
rowSpan = leafs[leafs.length - 1].depth - header.depth;
}
return (
<th
key={header.id}
colSpan={header.colSpan}
rowSpan={rowSpan}
style={{
padding: '12px',
textAlign: 'left',
fontSize: '0.75rem',
fontWeight: 'medium',
color: '#6b7280',
textTransform: 'uppercase',
letterSpacing: '0.05em',
backgroundColor: '#f9fafb',
border: '1px solid #e5e7eb',
}}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id} style={{
padding: '12px',
whiteSpace: 'nowrap',
fontSize: '0.875rem',
color: '#6b7280',
border: '1px solid #e5e7eb',
}}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
} |
Beta Was this translation helpful? Give feedback.
-
Repo: https://github.com/jacksonkasi1/FlexiSheet |
Beta Was this translation helpful? Give feedback.
-
Hi folks 👋
I'm having a bit of trouble understanding how
rowSpan
works for headers, especially when working with header groups.The column group demo renders header groups by looping over
table.getHeaderGroups()
, creating a<tr>
for each group, looping over group headers and returningnull
inside<th>
when the headerisPlaceholder
value istrue
, which results in empty header cells depending on the structureIdeally it should look like (at least in my use case)
To achieve that I'd have to
<th>
with a value of the depth found<th>
for the headers that are already "covered" by the rowSpan of the parentDoes someone know how to achieve this in a simpler way ?
Couldn't it possible to manually declare a rowSpan in columnDef, which would be taken into account when building the groups ?
I found here that header supports
rowSpan
, but I'm not sure how it's calculated, it always seem to be 0.What do you think ?
Edit :
I managed to make it work by adding a custom
rowSpan
in column meta in combination with the following render logic :But it feels kinda wrong and displays some header twice if you don't supply a
rowSpan
when needed.Here's a codesandbox if you want to tinker with it.
Beta Was this translation helpful? Give feedback.
All reactions