gp-grid-logo
Examples

Custom Renderers

Render custom React components inside grid cells and headers, including badges, charts, action menus, and any other interactive UI you need to embed today.

Customize how cells and headers are rendered with custom renderer functions.

Interactive Demo

This demo shows three custom renderers in action:

  • Status - Colored dot indicator (green/amber/gray)
  • Performance - Positive values in green, negative in red
  • Salary - Formatted as currency

Filters, sort comparisons, and copy-paste operate on the formatted value — the string users actually see — not the raw cell value. A cellRenderer only changes how a cell is painted; it does not change the value that powers filtering. Pair every custom renderer with a matching valueFormatter so the two stay in sync:

{
  field: "salary",
  cellDataType: "number",
  width: 140,
  cellRenderer: SalaryRenderer,
  valueFormatter: (value) => `$${(value as number).toLocaleString()}`,
}

Without the formatter, users filtering for "$82,000" on the Salary column would match nothing because the filter sees the raw 82000. See the full valueFormatter reference for signature, caveats, and more examples.

Cell Renderers

Global Cell Renderer

Apply a renderer to all cells:

import { Grid, type CellRendererParams } from "@gp-grid/react";

const MyCellRenderer = (params: CellRendererParams) => {
  return (
    <div className="flex items-center h-full px-2">
      {params.value?.toString()}
    </div>
  );
};

<Grid
  columns={columns}
  rowData={data}
  rowHeight={36}
  cellRenderer={MyCellRenderer}
/>

Per-Column Renderers (Inline)

Pass a renderer function directly in the column definition:

const StatusRenderer = (params: CellRendererParams) => {
  const status = params.value as string;
  const color = status === "Active" ? "green" : "red";

  return (
    <div className="flex items-center h-full px-2">
      <span
        className="w-2 h-2 rounded-full mr-2"
        style={{ backgroundColor: color }}
      />
      {status}
    </div>
  );
};

const columns: ColumnDefinition[] = [
  { field: "name", cellDataType: "text", width: 150 },
  {
    field: "status",
    cellDataType: "text",
    width: 120,
    cellRenderer: StatusRenderer,
  },
];

<Grid columns={columns} rowData={data} rowHeight={36} />

Per-Column Renderers (Registry)

Alternatively, register renderers by key and reference them by name. This is useful when the same renderer is shared across multiple columns:

const columns: ColumnDefinition[] = [
  { field: "name", cellDataType: "text", width: 150 },
  {
    field: "status",
    cellDataType: "text",
    width: 120,
    cellRenderer: "status"
  },
];

<Grid
  columns={columns}
  rowData={data}
  rowHeight={36}
  cellRenderers={{ status: StatusRenderer }}
/>

Header Renderers

Customize column headers:

import { type HeaderRendererParams } from "@gp-grid/react";

const MyHeaderRenderer = (params: HeaderRendererParams) => {
  return (
    <div className="flex items-center justify-between w-full h-full px-2">
      <span className="font-bold">{params.column.headerName}</span>
      {params.sortDirection && (
        <span>{params.sortDirection === "asc" ? "▲" : "▼"}</span>
      )}
    </div>
  );
};

<Grid
  columns={columns}
  rowData={data}
  rowHeight={36}
  headerRenderer={MyHeaderRenderer}
/>

Renderer Parameters

CellRendererParams

PropertyTypeDescription
valueCellValueCurrent cell value
rowDataTDataFull row data object
columnColumnDefinitionColumn definition
rowIndexnumberRow index
colIndexnumberColumn index
isActivebooleanIs the active cell
isSelectedbooleanIs in selection range
isEditingbooleanIs being edited

HeaderRendererParams

PropertyTypeDescription
columnColumnDefinitionColumn definition
colIndexnumberColumn index
sortDirectionSortDirection | undefinedCurrent sort direction
sortIndexnumber | undefinedMulti-sort order
sortablebooleanIs column sortable
filterablebooleanIs column filterable
hasFilterbooleanHas active filter
onSortfunctionTrigger sort
onFilterClickfunctionOpen filter popup