Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement horizontal virtualisation in tanstack table v8?

I am building a full scale, editable, sortable table using tanstack table. I have already added virtualisation to rows using the example provided at tanstack table website. However, I also want to implement horizontal virtualisation, and I am lost on ideas. The only thing that I could think of was virtualising th but that would virtualise the headers and not the entire table. Any ideas on how this could be solved?


`import {
  Cell,
  Column,
  ColumnDef,
  flexRender,
  getCoreRowModel,
  Header,
  Row,
  useReactTable,
} from '@tanstack/react-table';
import React, { useRef, useState } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { useVirtual } from 'react-virtual';
import { useListViewContext } from './context/ListViewContext';
import DraggableRow from './DraggableRow';
import './index.css';

export type Props = {
  columns: ColumnDef<any>[];
};

const Table: React.FC<Props> = ({ columns }) => {
  const { data, reorderRow } = useListViewContext();
  const [rowSelection, setRowSelection] = useState({});
  const [hoveredRow, setHoveredRow] = useState<string | null>(null);
  const [focusedCell, setFocusedCell] = useState<Cell<any, any> | null>(null);
  const tableContainerRef = useRef<HTMLDivElement>(null);
  const table = useReactTable({
    data,
    columns,
    state: {
      rowSelection,
    },
    enableRowSelection: true,
    onRowSelectionChange: setRowSelection,
    columnResizeMode: 'onChange',
    getCoreRowModel: getCoreRowModel(),
  });

  const { rows } = table.getRowModel();
  const [{ headers }] = table.getHeaderGroups();
  const mainHeaders = headers.slice(0, 3);
  const virtualizedHeaders = headers.slice(3);
  console.log(mainHeaders, virtualizedHeaders);
  const rowVirtualizer = useVirtual({
    parentRef: tableContainerRef,
    size: rows.length,
    overscan: 10,
  });
  // const colVirtualizer = useVirtual({
  //   horizontal: true,
  //   size: headers.length,
  //   // estimateSize: React.useCallback(() => {
  //   //   let totalWidth = 0;
  //   //   headerGroups[0].headers.forEach((header) => {
  //   //     totalWidth += header.getSize();
  //   //   });
  //   //   return totalWidth;
  //   // }, [headerGroups]),
  //   parentRef: tableContainerRef,
  //   overscan: 10,
  // });
  // const { virtualItems: virtualCols, totalSize: totalWidth } = colVirtualizer;

  const { virtualItems: virtualRows, totalSize } = rowVirtualizer;
  const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
  const paddingBottom =
    virtualRows.length > 0
      ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0)
      : 0;

  // const paddingLeft = virtualCols.length > 0 ? virtualCols?.[0]?.start || 0 : 0;
  // const paddingRight =
  //   virtualCols.length > 0
  //     ? totalWidth - (virtualCols?.[virtualCols.length - 1]?.end || 0)
  //     : 0;
  return (
    <DndProvider backend={HTML5Backend}>
      <div
        ref={tableContainerRef}
        className={`h-full mt-4 mx-5 relative overflow-x-auto`}
      >
        <table
          className="table-fixed absolute left-0 border-separate border-spacing-0"
          {...{
            style: {
              width: table.getCenterTotalSize(),
            },
          }}
        >
          <thead>
            {table?.getHeaderGroups().map((headerGroup) => (
              <tr key={headerGroup.id}>
                <th className="th w-6"></th>
                {headerGroup.headers.map((header) => (
                  <th
                    key={header.id}
                    {...{
                      className:
                        'th border-r-[0.4px] border-t-[0.4px] border-b border-grey5 text-xs 
                         p-2 bg-grey2 hover:bg-grey3 text-grey6',
                      style: {
                        width: header.getSize(),
                      },
                    }}
                  >
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext(),
                        )}
                    <div
                      {...{
                        onMouseDown: header.getResizeHandler(),
                        onTouchStart: header.getResizeHandler(),
                        className: `resizer ${
                          !header.column.getCanResize() ? 'hidden' : 'block'
                        } ${header.column.getIsResizing() ? 'isResizing' : ''}`,
                      }}
                    />
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody>
            {paddingTop > 0 && (
              <tr>
                <td style={{ height: `${paddingTop}px` }} />
              </tr>
            )}
            {virtualRows.map((virtualRow) => {
              const row = rows[virtualRow.index] as Row<any>;
              return (
                <DraggableRow
                  key={row.id}
                  row={row}
                  hoveredRow={hoveredRow}
                  focusedCell={focusedCell}
                  setFocusedCell={setFocusedCell}
                  setHoveredRow={setHoveredRow}
                  reorderRow={reorderRow}
                />
              );
            })}
            {paddingBottom > 0 && (
              <tr>
                <td style={{ height: `${paddingBottom}px` }} />
              </tr>
            )}
          </tbody>
        </table>
      </div>
    </DndProvider>
  );
};

export default Table;`

Expecting column virtualisation your text

like image 219
Upneet Singh Avatar asked Dec 06 '25 15:12

Upneet Singh


1 Answers

Could be too late, but still: There is an example in official documentation https://tanstack.com/virtual/v3/docs/examples/react/fixed, check for GridVirtualizerFixed implementation.

Tables are not so flexible as block elements, so the only option to scroll both head and content is to change the markup.

like image 120
underwonder Avatar answered Dec 08 '25 06:12

underwonder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!