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.

Overview

React Data Grid provides controlled sorting functionality. The grid handles UI interactions but you control the actual row ordering, giving you flexibility to implement server-side or client-side sorting.

Basic Setup

Enable sorting by marking columns as sortable and managing sort state:
import { useState } from 'react';
import { DataGrid, type Column, type SortColumn } from 'react-data-grid';

interface Row {
  id: number;
  name: string;
  email: string;
}

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

function MyGrid() {
  const [rows, setRows] = useState(initialRows);
  const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);

  return (
    <DataGrid
      columns={columns}
      rows={rows}
      sortColumns={sortColumns}
      onSortColumnsChange={setSortColumns}
    />
  );
}
Sorting is controlled: the grid does not reorder rows automatically. You must apply sorting logic to your rows based on sortColumns.

Column Configuration

sortable
boolean
default:false
Enable sorting for the column. Click the header to toggle sort direction.
sortDescendingFirst
boolean
default:false
Start with descending order on first click instead of ascending.
const columns: Column<Row>[] = [
  {
    key: 'date',
    name: 'Date',
    sortable: true,
    sortDescendingFirst: true // Click once for newest first
  }
];

Sort Props

sortColumns
readonly SortColumn[]
Array of currently sorted columns. Each entry contains:
  • columnKey: The column’s key
  • direction: Either 'ASC' or 'DESC'
onSortColumnsChange
(sortColumns: SortColumn[]) => void
Callback triggered when sorting changes.

Implementing Sort Logic

Apply sorting to your rows:
import { useMemo, useState } from 'react';
import { DataGrid, type SortColumn } from 'react-data-grid';

function MyGrid() {
  const [rows, setRows] = useState(initialRows);
  const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);

  const sortedRows = useMemo(() => {
    if (sortColumns.length === 0) return rows;

    return [...rows].sort((a, b) => {
      for (const sort of sortColumns) {
        const { columnKey, direction } = sort;
        const aValue = a[columnKey as keyof Row];
        const bValue = b[columnKey as keyof Row];

        if (aValue < bValue) {
          return direction === 'ASC' ? -1 : 1;
        }
        if (aValue > bValue) {
          return direction === 'ASC' ? 1 : -1;
        }
      }
      return 0;
    });
  }, [rows, sortColumns]);

  return (
    <DataGrid
      columns={columns}
      rows={sortedRows}
      sortColumns={sortColumns}
      onSortColumnsChange={setSortColumns}
    />
  );
}

Multi-Column Sorting

By default, the grid supports multi-column sorting with Ctrl + Click (or Cmd + Click on Mac):
// Click column header: Sort by that column
// Ctrl + Click another header: Add secondary sort
// Click sorted header again: Reverse direction
// Click sorted header third time: Remove from sort
The grid displays sort priority numbers when multiple columns are sorted.

Disable Multi-Column Sorting

Limit to single-column sorting:
function onSortColumnsChange(sortColumns: SortColumn[]) {
  setSortColumns(sortColumns.slice(-1)); // Keep only the last sorted column
}

<DataGrid
  columns={columns}
  rows={rows}
  sortColumns={sortColumns}
  onSortColumnsChange={onSortColumnsChange}
/>

Sort Direction Types

type SortDirection = 'ASC' | 'DESC';

interface SortColumn {
  readonly columnKey: string;
  readonly direction: SortDirection;
}

Custom Sort Icons

Customize the sort indicator appearance:
import {
  DataGrid,
  renderSortIcon,
  renderSortPriority,
  type Renderers,
  type RenderSortStatusProps
} from 'react-data-grid';

function CustomSortStatus(props: RenderSortStatusProps) {
  return (
    <div className="custom-sort">
      {renderSortIcon(props)}
      {renderSortPriority(props)}
    </div>
  );
}

const customRenderers: Renderers<Row, SummaryRow> = {
  renderSortStatus: CustomSortStatus
};

<DataGrid
  columns={columns}
  rows={rows}
  renderers={customRenderers}
  sortColumns={sortColumns}
  onSortColumnsChange={setSortColumns}
/>

Custom Header Cell

Full control over header rendering:
import { type RenderHeaderCellProps } from 'react-data-grid';

function CustomHeader({ column, sortDirection }: RenderHeaderCellProps<Row>) {
  return (
    <div className="custom-header">
      {column.name}
      {sortDirection && (
        <span className="sort-indicator">
          {sortDirection === 'ASC' ? ' ↑' : ' ↓'}
        </span>
      )}
    </div>
  );
}

const columns: Column<Row>[] = [
  {
    key: 'name',
    name: 'Name',
    sortable: true,
    renderHeaderCell: CustomHeader
  }
];

Server-Side Sorting

Implement server-side sorting by fetching data when sort changes:
import { useEffect, useState } from 'react';
import { DataGrid, type SortColumn } from 'react-data-grid';

function MyGrid() {
  const [rows, setRows] = useState([]);
  const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    async function fetchData() {
      setLoading(true);
      try {
        const params = new URLSearchParams();
        sortColumns.forEach((sort) => {
          params.append('sort', `${sort.columnKey}:${sort.direction.toLowerCase()}`);
        });
        
        const response = await fetch(`/api/data?${params}`);
        const data = await response.json();
        setRows(data);
      } finally {
        setLoading(false);
      }
    }

    fetchData();
  }, [sortColumns]);

  return (
    <DataGrid
      columns={columns}
      rows={rows}
      sortColumns={sortColumns}
      onSortColumnsChange={setSortColumns}
    />
  );
}

Advanced Sorting

Case-Insensitive String Sorting

const sortedRows = useMemo(() => {
  if (sortColumns.length === 0) return rows;

  return [...rows].sort((a, b) => {
    for (const sort of sortColumns) {
      const { columnKey, direction } = sort;
      const aValue = a[columnKey as keyof Row];
      const bValue = b[columnKey as keyof Row];

      // Handle strings case-insensitively
      const aCompare = typeof aValue === 'string' ? aValue.toLowerCase() : aValue;
      const bCompare = typeof bValue === 'string' ? bValue.toLowerCase() : bValue;

      if (aCompare < bCompare) {
        return direction === 'ASC' ? -1 : 1;
      }
      if (aCompare > bCompare) {
        return direction === 'ASC' ? 1 : -1;
      }
    }
    return 0;
  });
}, [rows, sortColumns]);

Null/Undefined Handling

const sortedRows = useMemo(() => {
  if (sortColumns.length === 0) return rows;

  return [...rows].sort((a, b) => {
    for (const sort of sortColumns) {
      const { columnKey, direction } = sort;
      const aValue = a[columnKey as keyof Row];
      const bValue = b[columnKey as keyof Row];

      // Handle null/undefined - push to end
      if (aValue == null && bValue == null) continue;
      if (aValue == null) return 1;
      if (bValue == null) return -1;

      if (aValue < bValue) {
        return direction === 'ASC' ? -1 : 1;
      }
      if (aValue > bValue) {
        return direction === 'ASC' ? 1 : -1;
      }
    }
    return 0;
  });
}, [rows, sortColumns]);

TypeScript Types

interface SortColumn {
  readonly columnKey: string;
  readonly direction: SortDirection;
}

type SortDirection = 'ASC' | 'DESC';

interface DataGridProps<R, SR = unknown, K extends Key = Key> {
  /** Array of sorted columns */
  sortColumns?: Maybe<readonly SortColumn[]>;
  
  /** Callback when sorting changes */
  onSortColumnsChange?: Maybe<(sortColumns: SortColumn[]) => void>;
}

interface Column<TRow, TSummaryRow = unknown> {
  /** Enable sorting for this column */
  readonly sortable?: Maybe<boolean>;
  
  /** Start with descending on first sort */
  readonly sortDescendingFirst?: Maybe<boolean>;
}

interface RenderHeaderCellProps<TRow, TSummaryRow = unknown> {
  column: CalculatedColumn<TRow, TSummaryRow>;
  sortDirection: SortDirection | undefined;
  priority: number | undefined;
  tabIndex: number;
}

Build docs developers (and LLMs) love