react-data-grid

repository·main·Indexed 27 days ago

https://github.com/comcast/react-data-grid

A high-performance, feature-rich, and customizable data grid React component supporting cell editing, column resizing, sorting, and tree data. It includes the TreeDataGrid component for hierarchical row grouping and provides hooks like useRowSelection and useHeaderRowSelection for managing selection state.

Tokens
10.5K
Snippets
32
Records
46
Agent score
92%

What's inside react-data-grid

  1. Optimize row updates for performance

    main

    When updating rows in your state, avoid creating new references for every row object. Instead, map through the existing rows and only create a new object for the row that actually changed. This allows the grid's internal memoization to skip re-rendering unchanged rows.

    // ✅ Good: Only changed row is re-rendered
    setRows(rows.map((row, idx) => (idx === targetIdx ? { ...row, updated: true } : row)));
    
    // ❌ Avoid: Creates new references for all rows, causing all visible rows to re-render
    setRows(rows.map((row) => ({ ...row })));
  2. Implement hierarchical grouping with TreeDataGrid

    main

    TreeDataGrid is a component built on top of DataGrid that implements the Treegrid pattern. It allows for hierarchical row grouping.

    Required Props

    • groupBy: An array of column keys to group by. The order determines the hierarchy.
    • rowGrouper: A function that groups rows by the specified column key. It must return an object where keys are group values and values are arrays of rows.
    • expandedGroupIds: A ReadonlySet of group IDs that are currently expanded.
    • onExpandedGroupIdsChange: A callback triggered when groups are expanded or collapsed.

    Keyboard Navigation

    • (Right Arrow): Expand a collapsed group row.
    • (Left Arrow): Collapse an expanded group row or navigate to the parent group.

    Limitations

    • onFill (drag-fill) is disabled.
    • isRowSelectionDisabled is not supported.
    • role and aria-rowcount are managed internally by TreeDataGrid.
    • Group columns are automatically frozen and cannot be unfrozen.
    • Cell copy/paste does not work on group rows.
    • columns must be a flat Column[] (no column groups).
    import { TreeDataGrid, type Column } from 'react-data-grid';
    
    interface Row {
      id: number;
      country: string;
      city: string;
      name: string;
    }
    
    const columns: readonly Column<Row>[] = [
      { key: 'country', name: 'Country' },
      { key: 'city', name: 'City' },
      { key: 'name', name: 'Name' }
    ];
    
    function MyGrid() {
      return (
        <TreeDataGrid
          columns={columns}
          rows={rows}
          groupBy={['country', 'city']}
          // ... other props
        />
      );
    }
  3. Configure text direction with direction

    main

    The direction prop sets the text direction of the grid. It defaults to 'ltr' (left-to-right).

    Setting direction to 'rtl' (right-to-left) results in:

    • Columns flowing from right to left.
    • Start-frozen columns pinned to the right, and end-frozen columns pinned to the left.
    • Column resize cursor shown on the left edge.
    • Scrollbar moved to the left.
  4. Implement custom `rowHeight` for `TreeDataGrid`

    main

    When using TreeDataGrid, you can provide a rowHeight function that receives RowHeightArgs. This allows you to return different heights based on whether the row is a standard row or a group row, or based on row properties.

    RowHeightArgs<TRow> types:

    • { type: 'ROW'; row: TRow }
    • { type: 'GROUP'; row: GroupRow<TRow> }
    function getRowHeight(args: RowHeightArgs<Row>): number {
      if (args.type === 'GROUP') {
        return 40;
      }
      return args.row.isLarge ? 60 : 35;
    }
    
    <TreeDataGrid rowHeight={getRowHeight} ... />
  5. Implement a custom cell editor with RenderEditCellProps

    main

    Use RenderEditCellProps to create custom editors for cells. This interface provides access to the current row, the column being edited, and methods to commit changes or close the editor.

    Key props:

    • onRowChange: Function to update the row data. Call with commitChanges: true to save.
    • onClose: Function to close the editor. Use commitChanges: true to save changes on close.
    import type { RenderEditCellProps } from 'react-data-grid';
    
    function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps<MyRow>) {
      return (
        <input
          autoFocus
          value={row[column.key]}
          onChange={(event) => onRowChange({ ...row, [column.key]: event.target.value })}
          onBlur={() => onClose(true)}
        />
      );
    }
  6. Handle cell keyboard events with CellKeyDownArgs

    main

    The onCellKeyDown handler receives CellKeyDownArgs, which changes shape depending on whether the cell is in ACTIVE or EDIT mode.

    • ACTIVE mode: Used for navigation. Provides setActivePosition to move focus.
    • EDIT mode: Used for data entry. Provides navigate and onClose (to commit or cancel changes).
    import type { CellKeyboardEvent, CellKeyDownArgs } from 'react-data-grid';
    
    function onCellKeyDown(args: CellKeyDownArgs<Row>, event: CellKeyboardEvent) {
      if (args.mode === 'EDIT' && event.key === 'Escape') {
        args.onClose(false); // Close without committing
        event.preventGridDefault();
      }
    }
  7. Prevent default grid behavior in mouse events

    main

    The CellMouseEvent object provides methods to prevent the grid's default behavior (like cell selection or focus) when handling specific clicks, such as on an 'actions' column.

    import type { CellMouseArgs, CellMouseEvent } from 'react-data-grid';
    
    function onCellClick(args: CellMouseArgs<Row>, event: CellMouseEvent) {
      if (args.column.key === 'actions') {
        event.preventGridDefault(); // Prevent cell focus
      }
    }
  8. Add a selection column using `SelectColumn`

    main

    SelectColumn is a pre-configured column that includes checkbox renderers for the header, regular rows, and grouped rows. To use it, include it in your columns array and manage the selectedRows state in your component.

    Note: You can identify or filter this column using the SELECT_COLUMN_KEY constant ('rdg-select-column').

    import { DataGrid, SelectColumn, type Column } from 'react-data-grid';
    
    const columns: readonly Column<Row>[] = [SelectColumn, ...otherColumns];
    
    function rowKeyGetter(row: Row) {
      return row.id;
    }
    
    function MyGrid() {
      return (
        <DataGrid
          columns={columns}
          rows={rows}
          rowKeyGetter={rowKeyGetter}
          selectedRows={selectedRows}
          onSelectedRowsChange={setSelectedRows}
        />
      );
    }
  9. Define `ColumnGroup` for grouped headers

    main

    Use ColumnGroup to create a group of columns that share a common header. This is useful for organizing related data under a single heading.

    Structure:

    • name: string | ReactElement: The group header name.
    • headerCellClass?: Maybe<string>: CSS class for the group header.
    • children: readonly ColumnOrColumnGroup<R, SR>[]: The columns or nested groups within this group.
    import type { ColumnOrColumnGroup } from 'react-data-grid';
    
    const columns: readonly ColumnOrColumnGroup<Row>[] = [
      {
        name: 'Personal Info',
        children: [
          { key: 'firstName', name: 'First Name' },
          { key: 'lastName', name: 'Last Name' }
        ]
      }
    ];
  10. Customize row height in TreeDataGrid

    main

    In TreeDataGrid, the rowHeight prop can be a function that receives RowHeightArgs<R>. This allows you to return different heights for regular rows versus group rows by checking the type property.

    RowHeightArgs<R>.type can be 'GROUP' or 'ROW'.

    function getRowHeight(args: RowHeightArgs<Row>): number {
      if (args.type === 'GROUP') {
        return 50; // Custom height for group rows
      }
      return 35; // Height for regular rows
    }
    
    <TreeDataGrid rowHeight={getRowHeight} ... />
  11. Use `renderToggleGroup` for grouping columns

    main

    renderToggleGroup is the default cell renderer used for columns configured for grouping (via the groupBy prop). It renders the expand/collapse toggle for tree data or grouped rows.

    import { renderToggleGroup, type Column } from 'react-data-grid';
    
    const columns: readonly Column<Row>[] = [
      {
        key: 'group',
        name: 'Group',
        renderGroupCell: renderToggleGroup
      }
    ];
  12. Provide default renderers via `DataGridDefaultRenderersContext`

    main

    Use DataGridDefaultRenderersContext to provide a set of default renderers to all DataGrid components within a specific part of your application tree. This is useful for implementing global themes or custom behaviors for checkboxes, sort icons, and sort status.

    Example implementation:

    import {
      DataGridDefaultRenderersContext,
      renderCheckbox,
      renderSortIcon,
      renderSortPriority,
      type Renderers
    } from 'react-data-grid';
    
    // custom implementations of renderers
    const defaultGridRenderers: Renderers<unknown, unknown> = {
      renderCheckbox,
      renderSortStatus(props) {
        return (
          <>
            {renderSortIcon(props)}
            {renderSortPriority(props)}
          </>
        );
      }
    };
    
    function AppProvider({ children }) {
      return (
        <DataGridDefaultRenderersContext value={defaultGridRenderers}>
          {children}
        </DataGridDefaultRenderersContext>
      );
    }