Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Comcast/react-data-grid/llms.txt

Use this file to discover all available pages before exploring further.

React Data Grid provides comprehensive keyboard navigation support, allowing users to efficiently navigate cells, edit data, and perform actions without using a mouse.

Basic Navigation

Arrow Keys

Navigate between cells using arrow keys:
import { DataGrid, type Column } from 'react-data-grid';

const columns: Column<Row>[] = [
  { key: 'id', name: 'ID' },
  { key: 'name', name: 'Name' },
  { key: 'email', name: 'Email' }
];

function MyGrid() {
  return <DataGrid columns={columns} rows={rows} />;
}
  • ↑ Up: Move to cell above
  • ↓ Down: Move to cell below
  • ← Left: Move to cell on the left
  • → Right: Move to cell on the right
The grid automatically scrolls to keep the selected cell visible during navigation.

Editing

Enter Edit Mode

Start editing cells using keyboard:
import { renderTextEditor } from 'react-data-grid';

const columns: Column<Row>[] = [
  {
    key: 'name',
    name: 'Name',
    renderEditCell: renderTextEditor
  }
];
Press Enter to start editing the selected cell.
// Default behavior
// Enter key opens editor on editable cells

While Editing

  • Enter: Save changes and close editor
  • Tab: Save changes and move to next cell
  • Click Outside: Save changes (default behavior)

Row Selection

Select rows using keyboard:
import { useState } from 'react';
import { DataGrid, SelectColumn } from 'react-data-grid';

function MyGrid() {
  const [selectedRows, setSelectedRows] = useState<ReadonlySet<number>>(new Set());
  
  const columns = [
    SelectColumn,
    { key: 'name', name: 'Name' },
    { key: 'email', name: 'Email' }
  ];
  
  return (
    <DataGrid
      columns={columns}
      rows={rows}
      rowKeyGetter={(row) => row.id}
      selectedRows={selectedRows}
      onSelectedRowsChange={setSelectedRows}
    />
  );
}
Shift+Space: Toggle row selectionFrom src/DataGrid.tsx:
// Select the row on Shift + Space
if (isSelectable && shiftKey && key === ' ') {
  const rowKey = rowKeyGetter(row);
  selectRow({ row, checked: !selectedRows.has(rowKey), isShiftClick: false });
  event.preventDefault(); // prevent scrolling
}

TreeGrid Navigation

TreeDataGrid provides additional keyboard navigation:
import { useState } from 'react';
import { TreeDataGrid, type Column } from 'react-data-grid';

function MyTreeGrid() {
  const [expandedGroupIds, setExpandedGroupIds] = useState<ReadonlySet<unknown>>(new Set());
  
  return (
    <TreeDataGrid
      columns={columns}
      rows={rows}
      groupBy={['category']}
      rowGrouper={rowGrouper}
      expandedGroupIds={expandedGroupIds}
      onExpandedGroupIdsChange={setExpandedGroupIds}
    />
  );
}
When a group row is focused:
  • → Right Arrow: Expand collapsed group
  • ← Left Arrow: Collapse expanded group
From src/TreeDataGrid.tsx:
if (
  idx === -1 &&
  ((event.key === leftKey && row.isExpanded) ||
   (event.key === rightKey && !row.isExpanded))
) {
  event.preventDefault();
  event.preventGridDefault();
  toggleGroup(row.id);
}

Custom Keyboard Behavior

Prevent Default Actions

Customize keyboard behavior using onCellKeyDown:
import type { CellKeyDownArgs, CellKeyboardEvent } from 'react-data-grid';

function handleCellKeyDown(
  args: CellKeyDownArgs<Row>,
  event: CellKeyboardEvent
) {
  if (args.mode === 'SELECT' && event.key === 'Enter') {
    // Prevent entering edit mode on Enter
    event.preventGridDefault();
    
    // Custom action instead
    console.log('Custom action for', args.row);
  }
}

<DataGrid
  columns={columns}
  rows={rows}
  onCellKeyDown={handleCellKeyDown}
/>
Customize Tab key behavior:
function handleCellKeyDown(
  args: CellKeyDownArgs<Row>,
  event: CellKeyboardEvent
) {
  if (args.mode === 'SELECT' && event.key === 'Tab') {
    // Prevent default tab navigation
    event.preventGridDefault();
    
    // Custom logic: skip non-editable columns
    const currentIdx = args.column.idx;
    const nextEditableIdx = columns.findIndex(
      (col, idx) => idx > currentIdx && col.renderEditCell
    );
    
    if (nextEditableIdx !== -1) {
      args.selectCell({
        idx: nextEditableIdx,
        rowIdx: args.rowIdx
      });
    }
  }
}

Custom Edit Triggers

Control when cells enter edit mode:
function handleCellClick(
  args: CellMouseArgs<Row>,
  event: CellMouseEvent
) {
  // Enter edit mode on single click
  if (args.column.renderEditCell) {
    args.selectCell(true); // true = enable editor
  }
}

<DataGrid
  columns={columns}
  rows={rows}
  onCellClick={handleCellClick}
/>
Only allow editing under certain conditions:
function handleCellKeyDown(
  args: CellKeyDownArgs<Row>,
  event: CellKeyboardEvent
) {
  if (args.mode === 'SELECT' && event.key === 'Enter') {
    // Only allow editing if user has permission
    if (!userHasEditPermission(args.row)) {
      event.preventGridDefault();
      alert('You do not have permission to edit this row');
      return;
    }
    
    // Allow default behavior (enter edit mode)
  }
}

Focus Management

The grid manages focus automatically:
// From src/DataGrid.tsx
useLayoutEffect(() => {
  if (shouldFocusCell) {
    if (selectedPosition.idx === -1) {
      focusRow(gridRef.current!);
    } else {
      focusCell(gridRef.current!);
    }
    setShouldFocusCell(false);
  }
}, [shouldFocusCell, selectedPosition.idx, gridRef]);

Programmatic Focus

Control focus programmatically:
import { useRef } from 'react';
import type { DataGridHandle } from 'react-data-grid';

function MyComponent() {
  const gridRef = useRef<DataGridHandle>(null);
  
  function focusCell(rowIdx: number, colIdx: number) {
    gridRef.current?.selectCell({ rowIdx, idx: colIdx }, { shouldFocusCell: true });
  }
  
  return (
    <>
      <button onClick={() => focusCell(0, 0)}>Focus first cell</button>
      <DataGrid
        ref={gridRef}
        columns={columns}
        rows={rows}
      />
    </>
  );
}

RTL Navigation

In RTL mode, horizontal navigation is reversed:
<DataGrid
  columns={columns}
  rows={rows}
  direction="rtl"
/>
From src/DataGrid.tsx:
const { leftKey, rightKey } = getLeftRightKey(direction);

// In RTL mode:
// - leftKey is 'ArrowRight'
// - rightKey is 'ArrowLeft'
Arrow key behavior automatically adjusts:
  • → Right: Moves left in RTL
  • ← Left: Moves right in RTL

Accessibility

ARIA Support

The grid implements proper ARIA attributes:
<div
  role="grid"
  aria-label="Data grid"
  aria-colcount={columns.length}
  aria-rowcount={rows.length + headerRowsCount}
  aria-multiselectable={isSelectable}
  tabIndex={-1} // Grid container is focusable
>
  <div role="row" aria-rowindex={1}>
    <div role="columnheader" aria-colindex={1} tabIndex={-1}>
      Column 1
    </div>
  </div>
  <div role="row" aria-rowindex={2} aria-selected={false}>
    <div role="gridcell" aria-colindex={1} tabIndex={0}>
      Cell content
    </div>
  </div>
</div>

Screen Reader Support

  • Grid role: Announces as data grid
  • Aria attributes: Provide context about position and selection
  • Focus management: Maintains logical focus order
  • Selection state: Announces selected rows
Provide proper labels for accessibility:
<DataGrid
  aria-label="Employee directory"
  aria-description="Searchable list of all employees with contact information"
  columns={columns}
  rows={rows}
/>

// Or with aria-labelledby
<>
  <h2 id="grid-title">Employee Directory</h2>
  <DataGrid
    aria-labelledby="grid-title"
    columns={columns}
    rows={rows}
  />
</>

API Reference

DataGrid Props

onCellKeyDown

onCellKeyDown?: (args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) => void
Description: Callback triggered when a key is pressed in a cell. Usage: Customize keyboard behavior or add custom shortcuts.

onSelectedCellChange

onSelectedCellChange?: (args: CellSelectArgs<R, SR>) => void
Description: Triggered when the selected cell changes.

CellKeyDownArgs

type CellKeyDownArgs<TRow, TSummaryRow = unknown> =
  | SelectCellKeyDownArgs<TRow, TSummaryRow>
  | EditCellKeyDownArgs<TRow, TSummaryRow>;

interface SelectCellKeyDownArgs<TRow, TSummaryRow> {
  mode: 'SELECT';
  column: CalculatedColumn<TRow, TSummaryRow> | undefined;
  row: TRow;
  rowIdx: number;
  selectCell: (position: Position, options?: SelectCellOptions) => void;
}

interface EditCellKeyDownArgs<TRow, TSummaryRow> {
  mode: 'EDIT';
  column: CalculatedColumn<TRow, TSummaryRow>;
  row: TRow;
  rowIdx: number;
  navigate: () => void;
  onClose: (commitChanges?: boolean, shouldFocusCell?: boolean) => void;
}

CellKeyboardEvent

type CellKeyboardEvent = CellEvent<React.KeyboardEvent<HTMLDivElement>>;

interface CellEvent<E> extends E {
  preventGridDefault: () => void;
  isGridDefaultPrevented: () => boolean;
}
Methods:
  • preventGridDefault(): Prevent the grid’s default keyboard behavior
  • isGridDefaultPrevented(): Check if default was prevented

DataGridHandle

interface DataGridHandle {
  element: HTMLDivElement | null;
  scrollToCell: (position: PartialPosition) => void;
  selectCell: (position: Position, options?: SelectCellOptions) => void;
}

Build docs developers (and LLMs) love