Custom Header, Footer, Filter, and Group CellsPremium
The KendoReact Grid lets you replace the cells in the header row, filter row, footer row, and group header and footer rows with custom cell components. Column header cells render as <th> elements and carry ARIA attributes for sorting and keyboard navigation. Filter, footer, and group cells render as <td> elements and use a separate set of attribute props.
You can replace any of these cell types by providing a custom cell component through the cells prop on Grid or GridColumn. The available cell types are:
headerCell—the column title cell in the header row.filterCell—the cell in the filter row below the header.footerCell—the cell in the optional footer row at the bottom.groupHeader—the cell that labels each group row when grouping is enabled.groupFooter—the cell that appears at the bottom of each group when group footers are enabled.
The following example shows all cell types customized at once. Each type receives a different custom component that applies custom colors and renders the default children content so the Grid's built-in sort icon, column menu, and grouping labels are preserved.
Custom Header Cells
A custom header cell component receives GridCustomHeaderCellProps. The most important props are:
thProps—The full set of HTML and ARIA attributes the Grid would apply to the<th>element by default. This includesaria-sort, the column identity needed for keyboard navigation, andcolSpanfor spanned headers.children—The default cell content rendered by the Grid, including the column title, sort indicator, column menu trigger, and column resize handle.
When implementing a custom header cell, you must render the outer element as HeaderThElement from @progress/kendo-react-data-tools and forward thProps to it. Rendering a plain <th> instead, or omitting thProps, will disconnect the column from the Grid's sort state, ARIA attributes, and keyboard focus management.
The following snippets show a custom header cell component and how to bind it to the Grid:
import * as React from 'react';
import { HeaderThElement } from '@progress/kendo-react-data-tools';
import { GridCustomHeaderCellProps } from '@progress/kendo-react-grid';
const CustomHeaderCell = (props: GridCustomHeaderCellProps) => (
<HeaderThElement columnId={props.thProps?.columnId || ''} {...props.thProps} style={{ color: '#533291' }}>
{props.children}
</HeaderThElement>
);Custom Filter Cells
A custom filter cell component receives GridCustomFilterCellProps. Unlike header cells, filter row cells are rendered as <td> elements with a role="gridcell" by default. The Grid passes both thProps and tdProps to the custom filter cell and both point to the same navigation attributes object, including the column ID and keyboard navigation hooks.
You can use HeaderThElement with thProps as shown in the example below — the role="gridcell" attribute in thProps will override the native <th> role on the rendered element so accessibility semantics remain correct.
The children prop contains the default filter input the Grid would render. If you render children, the built-in filter input remains functional and you only affect the cell's outer element. If you omit children and render your own control, you take responsibility for calling props.onChange with the appropriate filter descriptor.
The following snippets show a minimal custom filter cell and how to bind it to the Grid:
import * as React from 'react';
import { HeaderThElement } from '@progress/kendo-react-data-tools';
import { GridCustomFilterCellProps } from '@progress/kendo-react-grid';
const CustomFilterCell = (props: GridCustomFilterCellProps) => (
<HeaderThElement columnId={props.thProps?.columnId || ''} {...props.thProps}>
{props.children}
</HeaderThElement>
);Custom Footer Cells
A custom footer cell component receives GridCustomFooterCellProps. Footer cells render as <td> elements, so the relevant attribute prop here is tdProps rather than thProps. Forwarding tdProps is important when the Grid has locked (sticky) columns — it carries the positioning styles that keep locked cells aligned.
The field prop identifies which column the footer cell belongs to, making it straightforward to compute and display aggregates such as sum, average, minimum, or maximum values for that field.
The following snippets show a custom footer cell that renders aggregates and how to bind it to the Grid:
import * as React from 'react';
import { GridCustomFooterCellProps } from '@progress/kendo-react-grid';
const CustomFooterCell = (props: GridCustomFooterCellProps) => {
const field = props.field || '';
const values = data.map((item) => item[field]);
const min = Math.min(...values);
const max = Math.max(...values);
return (
<td {...props.tdProps}>
min: {min}, max: {max}
</td>
);
};Custom Group Header and Group Footer Cells
Group header and group footer cells both receive GridCustomCellProps and also render as <td> elements. The key props here are dataItem, which contains the group descriptor including the grouped field and its value, and tdProps for forwarding the cell's structural attributes.
children in group cells contains the default group label or footer content the Grid would render. Rendering children preserves the default label text, expand/collapse icon, and aggregate display.
import * as React from 'react';
import { GridCustomCellProps } from '@progress/kendo-react-grid';
const CustomGroupHeaderCell = (props: GridCustomCellProps) => (
<td {...props.tdProps} style={{ color: '#014830', backgroundColor: '#4a9d93' }}>
{props.children}
</td>
);Column-Level vs. Grid-Level Registration
The cells prop is available on both the Grid component and individual GridColumn components. When set on Grid, the custom cell applies to every column. When set on GridColumn, it applies only to that column and overrides the Grid-level setting for that column.
{/* Applied to every column */}
<Grid cells={{ headerCell: CustomHeaderCell }}>
{/* Overrides only for this column */}
<GridColumn field="UnitPrice" cells={{ footerCell: CustomUnitPriceFooterCell }} />
</Grid>