Skip to content

Columns

Configure column behavior, resizing, reordering, and display options.

Column Definition

tsx
interface ColumnDef<T> {
  field: keyof T | string;           // Data field
  header: string;                    // Header text
  width?: string;                    // CSS width (e.g., '200px', '20%')
  align?: 'left' | 'right' | 'center';
  sortable?: boolean;                // Default: true
  flashOnChange?: boolean;           // Flash on value changes
  formatter?: (value: unknown, row: T) => ReactNode;
  cellClass?: (value: unknown, row: T) => string;
  resizable?: boolean;               // Per-column resize control
  reorderable?: boolean;             // Per-column reorder control
  minWidth?: number;                 // Minimum width in px
  maxWidth?: number;                 // Maximum width in px
}

Basic Configuration

tsx
const columns = [
  { field: 'symbol', header: 'Symbol', width: '100px' },
  { field: 'name', header: 'Name', width: '200px' },
  { field: 'price', header: 'Price', align: 'right', width: '100px' },
];

Nested Fields

Access nested object properties with dot notation:

tsx
interface User {
  id: number;
  profile: {
    name: string;
    email: string;
  };
  address: {
    city: string;
  };
}

const columns = [
  { field: 'profile.name', header: 'Name' },
  { field: 'profile.email', header: 'Email' },
  { field: 'address.city', header: 'City' },
];

Column Resizing

Enable Resizing

tsx
<DataGrid
  data={data}
  columns={columns}
  rowKey="id"
  resizable
/>

Controlled Widths

Persist column widths in state or storage:

tsx
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({
  symbol: 100,
  name: 200,
  price: 100,
});

<DataGrid
  data={data}
  columns={columns}
  rowKey="id"
  resizable
  columnWidths={columnWidths}
  onColumnResize={(field, width) =>
    setColumnWidths(prev => ({ ...prev, [field]: width }))
  }
/>

Min/Max Constraints

tsx
<DataGrid
  data={data}
  columns={columns}
  rowKey="id"
  resizable
  minColumnWidth={80}   // Global minimum
  maxColumnWidth={400}  // Global maximum
/>

// Or per-column
const columns = [
  { field: 'symbol', header: 'Symbol', minWidth: 60, maxWidth: 150 },
  { field: 'description', header: 'Description', minWidth: 200 },
];

Visual Feedback

When resizing hits a limit, the resize handle turns red and the cursor shows not-allowed.

Disable for Specific Columns

tsx
const columns = [
  { field: 'symbol', header: 'Symbol', resizable: false },  // Fixed width
  { field: 'name', header: 'Name' },  // Resizable
  { field: 'price', header: 'Price' },  // Resizable
];

Column Reordering

Enable Reordering

tsx
<DataGrid
  data={data}
  columns={columns}
  rowKey="id"
  reorderable
/>

Controlled Order

Persist column order:

tsx
const [columnOrder, setColumnOrder] = useState(['symbol', 'name', 'price']);

<DataGrid
  data={data}
  columns={columns}
  rowKey="id"
  reorderable
  columnOrder={columnOrder}
  onColumnReorder={setColumnOrder}
/>

Save to Local Storage

tsx
function usePersistedColumnOrder(key: string, defaultOrder: string[]) {
  const [order, setOrder] = useState<string[]>(() => {
    const saved = localStorage.getItem(key);
    return saved ? JSON.parse(saved) : defaultOrder;
  });

  const handleReorder = (newOrder: string[]) => {
    setOrder(newOrder);
    localStorage.setItem(key, JSON.stringify(newOrder));
  };

  return [order, handleReorder] as const;
}

// Usage
const [columnOrder, setColumnOrder] = usePersistedColumnOrder(
  'my-grid-columns',
  ['symbol', 'name', 'price']
);

Disable for Specific Columns

tsx
const columns = [
  { field: 'symbol', header: 'Symbol', reorderable: false },  // Pinned
  { field: 'name', header: 'Name' },  // Can be reordered
  { field: 'price', header: 'Price' },  // Can be reordered
];

Alignment

tsx
const columns = [
  { field: 'symbol', header: 'Symbol', align: 'left' },   // Default
  { field: 'name', header: 'Name', align: 'center' },
  { field: 'price', header: 'Price', align: 'right' },    // Numbers
];

Sorting

Columns are sortable by default. Disable sorting for specific columns:

tsx
const columns = [
  { field: 'symbol', header: 'Symbol', sortable: true },   // Sortable (default)
  { field: 'actions', header: 'Actions', sortable: false }, // Not sortable
];

Custom Formatters

Return a string or React element:

tsx
const columns = [
  {
    field: 'price',
    header: 'Price',
    formatter: (value) => `$${value.toFixed(2)}`,
  },
  {
    field: 'change',
    header: 'Change',
    formatter: (value, row) => (
      <span style={{ color: value >= 0 ? 'green' : 'red' }}>
        {value >= 0 ? '+' : ''}{value.toFixed(2)}%
      </span>
    ),
  },
  {
    field: 'status',
    header: 'Status',
    formatter: (value) => {
      const colors = { active: 'green', pending: 'yellow', inactive: 'gray' };
      return <span className={`status-${value}`}>{value}</span>;
    },
  },
];

Cell Classes

Apply conditional CSS classes:

tsx
const columns = [
  {
    field: 'pnl',
    header: 'P&L',
    cellClass: (value) => value >= 0 ? 'positive' : 'negative',
  },
  {
    field: 'status',
    header: 'Status',
    cellClass: (value, row) => {
      if (row.urgent) return 'cell-urgent';
      return `status-${value}`;
    },
  },
];
css
.positive { color: var(--grid-bid); }
.negative { color: var(--grid-ask); }
.cell-urgent { background: rgba(239, 68, 68, 0.2); }

Flash Highlighting

Enable flash effects for real-time data:

tsx
const columns = [
  { field: 'symbol', header: 'Symbol' },  // No flash
  { field: 'price', header: 'Price', flashOnChange: true },
  { field: 'volume', header: 'Volume', flashOnChange: true },
];

Values flash:

  • Green when value increases
  • Red when value decreases

See Flash Highlighting for details.

Released under the MIT License.