T
TanStack•2y ago
rival-black

Help with CSS for resizing columns

edit: repro: https://stackblitz.com/edit/tanstack-table-7djbwc?file=src/main.tsx Anyone mind taking a look With this resize in SS #2 you can see the columns sizes are off. The internals are { actions: 1165, firstName: 0, nickName: 817 } but you can see firstName is not the 60px width. Also when i add style={{ width: table.getTotalSize() }} my table doesn't take up w-full like it did before (i believe all the cols are at 120px while the "default" size is 150. When I don't use getTotalSize(), the columns don't adjust (but the code does)
export function DataTable<TData, TValue>({
columns,
data,
initialSearchParams,
}: DataTableProps<TData, TValue>) {

const table = useReactTable({
data,
columns,
filterFns: {
fuzzy: fuzzyFilter,
},
defaultColumn: {
minSize: 60,
maxSize: 800,
},
columnResizeMode: 'onChange',

getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onPaginationChange: setPagination,
onGlobalFilterChange: setGlobalFilter,

state: {
pagination: { pageIndex: page - 1, pageSize: count },
globalFilter,
},

initialState: {
// NavLink sets the initial search params
pagination: {
pageIndex: initialSearchParams.page - 1,
pageSize: initialSearchParams.count,
},
},
debugTable: true,
debugHeaders: true,
debugColumns: true,
})


const columnSizeVars = useMemo(() => {
// same as example
}, [table.getState().columnSizingInfo])

console.log(globalFilter)
...
export function DataTable<TData, TValue>({
columns,
data,
initialSearchParams,
}: DataTableProps<TData, TValue>) {

const table = useReactTable({
data,
columns,
filterFns: {
fuzzy: fuzzyFilter,
},
defaultColumn: {
minSize: 60,
maxSize: 800,
},
columnResizeMode: 'onChange',

getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onPaginationChange: setPagination,
onGlobalFilterChange: setGlobalFilter,

state: {
pagination: { pageIndex: page - 1, pageSize: count },
globalFilter,
},

initialState: {
// NavLink sets the initial search params
pagination: {
pageIndex: initialSearchParams.page - 1,
pageSize: initialSearchParams.count,
},
},
debugTable: true,
debugHeaders: true,
debugColumns: true,
})


const columnSizeVars = useMemo(() => {
// same as example
}, [table.getState().columnSizingInfo])

console.log(globalFilter)
...
StackBlitz
Shadcn DataTable Column Resizing Performant Example (forked) - Stac...
Run official live example code for Table Column Resizing Performant, created by Tanstack on StackBlitz
No description
No description
9 Replies
rival-black
rival-blackOP•2y ago
return (
<div
className='flex overflow-auto flex-col p-4 w-full h-full rounded-md border'
>
<Table className='' style={{ ...columnSizeVars, width: table.getTotalSize() }}>
<TableHeader className=''>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className=''>
{headerGroup.headers.map((header) => {
return (
<TableHead
key={header.id}
style={{ width: `calc(var(--header-${header.id}-size)))` }}
className='relative border border-zinc-300'
>
{header.isPlaceholder
? null
: flexRender(header.column.columnDef.header, header.getContext())}
<div
onDoubleClick={() => header.column.resetSize()}
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={cn(
'hover:bg-red-500 h-12 w-1 absolute top-0 right-0 px-2 cursor-col-resize',
header.column.getIsResizing() ? 'bg-blue-500 ' : '',
)}
/>
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
return (
<div
className='flex overflow-auto flex-col p-4 w-full h-full rounded-md border'
>
<Table className='' style={{ ...columnSizeVars, width: table.getTotalSize() }}>
<TableHeader className=''>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className=''>
{headerGroup.headers.map((header) => {
return (
<TableHead
key={header.id}
style={{ width: `calc(var(--header-${header.id}-size)))` }}
className='relative border border-zinc-300'
>
{header.isPlaceholder
? null
: flexRender(header.column.columnDef.header, header.getContext())}
<div
onDoubleClick={() => header.column.resetSize()}
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={cn(
'hover:bg-red-500 h-12 w-1 absolute top-0 right-0 px-2 cursor-col-resize',
header.column.getIsResizing() ? 'bg-blue-500 ' : '',
)}
/>
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<MemoizedTableBody className='overflow-auto'>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className='border border-zinc-300'
style={{ width: `calc(var(--col-${cell.column.id}-size))` }}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
</MemoizedTableBody>
</Table>
</div>
)
<MemoizedTableBody className='overflow-auto'>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className='border border-zinc-300'
style={{ width: `calc(var(--col-${cell.column.id}-size))` }}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
</MemoizedTableBody>
</Table>
</div>
)
@KevinVandy I added a repro https://stackblitz.com/edit/tanstack-table-7djbwc?file=src/main.tsx based on your example https://tanstack.com/table/latest/docs/framework/react/examples/column-resizing-performant Would you mind taking a quick look? You'll notice when you resize a col, it resizes the other columns (but the values in columnSizing don't adjust. I think its maybe a way im applying CSS but not totally sure
national-gold
national-gold•2y ago
why don't the <th> elements have a width style? You just had a bunch of problems with your table head and table styles Don't delete the * 1px. That's important
rival-black
rival-blackOP•2y ago
it looks like i had a typo and forgot to pass in 1px , thats one of those problems lol
national-gold
national-gold•2y ago
got it working
rival-black
rival-blackOP•2y ago
mind sharing what you did?
national-gold
national-gold•2y ago
Simply fixed those styles with the proper* 1px calc and correct ending parenthesis Also correct colSpan on the headers
rival-black
rival-blackOP•2y ago
🙌 thanks! that was what i was missing colSpan={header.colSpan} in TableHead
rival-black
rival-blackOP•2y ago
With <Table className='overflow-auto' style={{ ...columnSizeVars, width: table.getTotalSize() }}> getTotalSize is setting it to the initial size of all the columns as the default of 150 or 200 as I understand. Do you think the best approach to evenly distribute teh size of the columsn within a parent to use a ref and useeffect to set it on load?
No description
rival-black
rival-blackOP•2y ago
@KevinVandy actually what prob makes more sense for my usecase is distrbuting only the non-actions/goTo columns across the parent element. I'm trying to do something like this but columnDef = 970px while my logic has the parent width of 1022px.
const columnSizeVars = useMemo(() => {
const headers = table.getFlatHeaders()
const fixedColumns = ['goTo', 'actions']
let fixedColumnsWidth = 0

const colSizes: { [key: string]: number } = {}

for (let i = 0; i < headers.length; i++) {
const header = headers[i]
if (header && parentTableWrapperRef.current) {
if (fixedColumns.includes(header.id)) {
colSizes[`--header-${header.id}-size`] = header.getSize()
colSizes[`--col-${header.column.id}-size`] = header.column.getSize()
fixedColumnsWidth += header.getSize()
}
}
}
console.log(fixedColumnsWidth)

const parentWidth = parentTableWrapperRef.current?.offsetWidth || 0
const remainingWidth = parentWidth - fixedColumnsWidth
const remainingColumns = headers.length - fixedColumns.length
const remainingColumnWidth = remainingColumns > 0 ? remainingWidth / remainingColumns : 0
console.log({ parentWidth, remainingWidth, remainingColumns, remainingColumnWidth })
console.log(remainingColumnWidth * remainingColumns + fixedColumnsWidth)

for (let i = 0; i < headers.length; i++) {
const header = headers[i]
if (header && !fixedColumns.includes(header.id)) {
colSizes[`--header-${header.id}-size`] = remainingColumnWidth
colSizes[`--col-${header.column.id}-size`] = remainingColumnWidth
}
}
console.log('Column Sizes:', colSizes)

return colSizes
}, [table.getState().columnSizingInfo])
const columnSizeVars = useMemo(() => {
const headers = table.getFlatHeaders()
const fixedColumns = ['goTo', 'actions']
let fixedColumnsWidth = 0

const colSizes: { [key: string]: number } = {}

for (let i = 0; i < headers.length; i++) {
const header = headers[i]
if (header && parentTableWrapperRef.current) {
if (fixedColumns.includes(header.id)) {
colSizes[`--header-${header.id}-size`] = header.getSize()
colSizes[`--col-${header.column.id}-size`] = header.column.getSize()
fixedColumnsWidth += header.getSize()
}
}
}
console.log(fixedColumnsWidth)

const parentWidth = parentTableWrapperRef.current?.offsetWidth || 0
const remainingWidth = parentWidth - fixedColumnsWidth
const remainingColumns = headers.length - fixedColumns.length
const remainingColumnWidth = remainingColumns > 0 ? remainingWidth / remainingColumns : 0
console.log({ parentWidth, remainingWidth, remainingColumns, remainingColumnWidth })
console.log(remainingColumnWidth * remainingColumns + fixedColumnsWidth)

for (let i = 0; i < headers.length; i++) {
const header = headers[i]
if (header && !fixedColumns.includes(header.id)) {
colSizes[`--header-${header.id}-size`] = remainingColumnWidth
colSizes[`--col-${header.column.id}-size`] = remainingColumnWidth
}
}
console.log('Column Sizes:', colSizes)

return colSizes
}, [table.getState().columnSizingInfo])
Tried this by adding a loading state as well but totalColumnSize is the array that adds up to the 970px instead of the 1022px. Curious to hear if you had a better recommendation
useEffect(() => {
table.setColumnSizing(columnSizeVars)
const totalColumnSize = table.getAllColumns().map((c) => c.columnDef?.size)
console.log(totalColumnSize)
setLoading(false)
}, [columnSizeVars, table])
useEffect(() => {
table.setColumnSizing(columnSizeVars)
const totalColumnSize = table.getAllColumns().map((c) => c.columnDef?.size)
console.log(totalColumnSize)
setLoading(false)
}, [columnSizeVars, table])

Did you find this page helpful?