ShakibDShy

Virtualized Body 🚀

A high-performance table body component that efficiently renders large datasets through virtualization

Virtualized Body 🚀

The VirtualizedBody component is a performance-optimized version of the table body that only renders visible rows, making it perfect for handling large datasets efficiently. It uses virtualization techniques to maintain smooth scrolling and responsive performance.

Features ✨

  • 🎯 Virtual scrolling for large datasets
  • 📏 Fixed and dynamic row heights
  • 🔄 Infinite scrolling support
  • ⚡ Optimized performance
  • 🎨 Customizable styling
  • ♿ Full accessibility support
  • 📱 Touch device support

Basic Usage

import { VirtualizedBody } from '@shakibdshy/react-tablegrid';
 
function MyVirtualizedTable() {
  const tableInstance = useTableGrid({
    columns,
    data,
  });
 
  return (
    <VirtualizedBody
      tableInstance={tableInstance}
      config={{
        enabled: true,
        rowHeight: 48,
        overscan: 5,
      }}
    />
  );
}

Props

Required Props

tableInstance

The table instance from useTableGrid hook that manages the table state.

const tableInstance = useTableGrid<YourDataType>({
  columns,
  data,
});
 
<VirtualizedBody tableInstance={tableInstance} />

config

Configuration object for virtualization settings.

<VirtualizedBody
  config={{
    enabled: true,        // Enable virtualization
    rowHeight: 48,       // Height of each row in pixels
    overscan: 5,         // Number of rows to render outside visible area
    scrollingDelay: 150, // Optional: Delay before updating scroll position
    onEndReached: () => {}, // Optional: Called when reaching the end
    getRowHeight: (index) => number, // Optional: Dynamic row height function
  }}
  tableInstance={tableInstance}
/>

Optional Props

className

Add custom CSS classes to the virtualized body container.

<VirtualizedBody
  className="custom-body"
  tableInstance={tableInstance}
/>

bodyRowClassName

Add custom CSS classes to all virtualized rows.

<VirtualizedBody
  bodyRowClassName="custom-row"
  tableInstance={tableInstance}
/>

bodyCellClassName

Add custom CSS classes to all cells in virtualized rows.

<VirtualizedBody
  bodyCellClassName="custom-cell"
  tableInstance={tableInstance}
/>

style

Add custom inline styles to the container.

<VirtualizedBody
  style={{ height: '500px' }}
  tableInstance={tableInstance}
/>

withoutTailwind

Use without Tailwind CSS styling.

  • Type: boolean
  • Default: false
<VirtualizedBody
  withoutTailwind={true}
  tableInstance={tableInstance}
/>

customRender

Custom render functions for rows and loading state.

<VirtualizedBody
  customRender={{
    row: CustomRow,
    loading: () => <CustomLoadingState />,
  }}
  tableInstance={tableInstance}
/>

components

Component overrides for loading state.

<VirtualizedBody
  components={{
    LoadingState: CustomLoadingComponent,
  }}
  tableInstance={tableInstance}
/>

Features

Scrolling to Specific Rows

Use the ref to programmatically scroll to specific rows:

function ScrollableTable() {
  const virtualizedRef = useRef<VirtualizedBodyHandle>(null);
 
  const scrollToRow = (index: number) => {
    virtualizedRef.current?.scrollTo(index);
  };
 
  return (
    <>
      <button onClick={() => scrollToRow(50)}>
        Scroll to Row 50
      </button>
      <VirtualizedBody
        ref={virtualizedRef}
        tableInstance={tableInstance}
        config={{
          enabled: true,
          rowHeight: 48,
          overscan: 5,
        }}
      />
    </>
  );
}

Infinite Loading

Implement infinite scrolling with the onEndReached callback:

function InfiniteLoadingTable() {
  const [data, setData] = useState([]);
  const tableInstance = useTableGrid({
    columns,
    data,
  });
 
  const loadMore = useCallback(() => {
    fetchMoreData().then(newData => {
      setData(prev => [...prev, ...newData]);
    });
  }, []);
 
  return (
    <VirtualizedBody
      tableInstance={tableInstance}
      config={{
        enabled: true,
        rowHeight: 48,
        overscan: 5,
        onEndReached: loadMore,
      }}
    />
  );
}

Dynamic Row Heights

Support varying row heights with a height calculation function:

function DynamicHeightTable() {
  const getRowHeight = useCallback((index: number) => {
    const row = data[index];
    return row.content.length > 100 ? 96 : 48;
  }, [data]);
 
  return (
    <VirtualizedBody
      tableInstance={tableInstance}
      config={{
        enabled: true,
        rowHeight: 48, // Default height
        overscan: 5,
        getRowHeight, // Dynamic height function
      }}
    />
  );
}

Styling

With Tailwind (Default)

<VirtualizedBody
  className="relative overflow-auto scrollbar-thin"
  bodyRowClassName="hover:bg-gray-50"
  bodyCellClassName="px-4 py-2"
  tableInstance={tableInstance}
/>

Without Tailwind

<VirtualizedBody
  withoutTailwind={true}
  className="rtg-virtualized-body"
  bodyRowClassName="rtg-virtualized-row"
  bodyCellClassName="rtg-virtualized-cell"
  tableInstance={tableInstance}
/>

Loading States

The component handles loading states automatically:

<VirtualizedBody
  tableInstance={tableInstance}
  components={{
    LoadingState: () => (
      <div className="flex items-center justify-center p-8">
        <LoadingSpinner />
      </div>
    ),
  }}
/>

Accessibility ♿

The VirtualizedBody component implements these accessibility features:

  • role="rowgroup" for the container
  • role="presentation" for virtualized content
  • aria-label for clear context
  • aria-busy during loading states
  • aria-live for dynamic content updates
  • Touch device support with smooth scrolling

Best Practices 💡

  1. Set appropriate row heights for your content
  2. Use reasonable overscan values (3-10 rows)
  3. Implement loading states for better UX
  4. Handle scroll performance with debouncing
  5. Consider window resize events
  6. Test with different data sizes
  7. Maintain accessibility features

Integration with TableGrid

The VirtualizedBody is typically used within the TableGrid component:

function MyTable() {
  return (
    <TableGrid
      columns={columns}
      data={largeDataset}
      virtualization={{
        enabled: true,
        rowHeight: 48,
        overscan: 5,
      }}
      // VirtualizedBody will be automatically used
      // when virtualization is enabled
    />
  );
}

Last updated on