Customising Cell and Row Group values Copy Link
By default, the values exported to Excel will be formatted via the Using the Value Formatter for Export feature.
The grid cell and row group values can be customised specifically for Excel export using the following function params for a call to exportDataAsExcel API method or in the defaultExcelExportParams.
gridApi.exportDataAsExcel({
processCellCallback(params) {
const value = params.value
return value === undefined ? '' : `_${value}_`
},
processRowGroupCallback(params) {
return `row group: ${params.node.key}`
}
})See below the functions on the ExcelExportParams interface to customise exported grid cell and row group values.
A callback function invoked once per cell in the grid. Return a string value to be displayed in the export. For example this is useful for formatting date values.
|
A callback function invoked once per row group. Return a string to be displayed in the group cell.
|
The following example shows Excel customisations where the exported document has the following:
- All row groups with the prefix
row group: - All cell values surrounded by
_, unless they areundefined, in which case they are empty
When using row grouping while hiding open parents (groupHideOpenParents=true), export to Excel doesn't export the group rows as collapsible groups in Excel. Instead, all exported rows are on the same level and cannot be expanded/collapsed in Excel.
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
CsvExportModule,
ExcelExportParams,
GridApi,
GridOptions,
GridReadyEvent,
ModuleRegistry,
NumberFilterModule,
ProcessCellForExportParams,
ProcessRowGroupForExportParams,
UseGroupTotalRow,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ContextMenuModule,
ExcelExportModule,
RowGroupingModule,
SetFilterModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
const modules = [
NumberFilterModule,
ClientSideRowModelModule,
CsvExportModule,
ExcelExportModule,
ColumnMenuModule,
ContextMenuModule,
RowGroupingModule,
SetFilterModule,
];
const getParams: () => ExcelExportParams = () => ({
processCellCallback(params: ProcessCellForExportParams): string {
const value = params.value;
return value === undefined ? "" : `_${value}_`;
},
processRowGroupCallback(params: ProcessRowGroupForExportParams): string {
const { node } = params;
if (!node.footer) {
return `row group: ${node.key}`;
}
const isRootLevel = node.level === -1;
if (isRootLevel) {
return "Grand Total";
}
return `Sub Total (${node.key})`;
},
});
const GridExample = () => {
const gridRef = useRef<AgGridReact<IOlympicData>>(null);
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<IOlympicData[]>();
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "athlete", minWidth: 200 },
{ field: "country", minWidth: 200, rowGroup: true, hide: true },
{ field: "sport", minWidth: 150 },
{ field: "gold", aggFunc: "sum" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
filter: true,
minWidth: 150,
flex: 1,
};
}, []);
const popupParent = useMemo<HTMLElement | null>(() => {
return document.body;
}, []);
const defaultExcelExportParams = useMemo<ExcelExportParams>(() => {
return getParams();
}, []);
const onGridReady = useCallback((params: GridReadyEvent) => {
fetch("https://www.ag-grid.com/example-assets/small-olympic-winners.json")
.then((resp) => resp.json())
.then((data: IOlympicData[]) =>
setRowData(data.filter((rec: any) => rec.country != null)),
);
}, []);
const onBtExport = useCallback(() => {
gridRef.current!.api.exportDataAsExcel(getParams());
}, [getParams]);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div className="container">
<div>
<button
onClick={onBtExport}
style={{ margin: "5px 0px", fontWeight: "bold" }}
>
Export to Excel
</button>
</div>
<div className="grid-wrapper">
<div style={gridStyle}>
<AgGridReact<IOlympicData>
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
groupTotalRow={"bottom"}
grandTotalRow={"bottom"}
popupParent={popupParent}
defaultExcelExportParams={defaultExcelExportParams}
onGridReady={onGridReady}
/>
</div>
</div>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
.details > label {
margin-bottom: 10px;
}
.details > label:first-of-type {
margin-top: 10px;
}
.details > label:last-of-type {
margin-bottom: 0;
}
.option {
display: block;
margin: 5px 10px 5px 0;
}
.grid-wrapper {
display: flex;
flex: 1 1 0px;
}
.grid-wrapper > div {
width: 100%;
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.columns {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
}
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} Customising Column Headers and Group Header Values Copy Link
The column headers and group headers exported to Excel can be customised using the following function params for a call to exportDataAsExcel API method or in the defaultExcelExportParams.
gridApi.exportDataAsExcel({
processGroupHeaderCallback(params) {
return `group header: ${params.gridApi.getDisplayNameForColumnGroup(params.columnGroup, null)}`
},
processHeaderCallback(params) {
return `header: ${params.api.getDisplayNameForColumn(params.column, null)}`
}
});See below the functions on the ExcelExportParams interface to customise exported column group headers and headers.
A callback function invoked once per column. Return a string to be displayed in the column header.
|
A callback function invoked once per column group. Return a string to be displayed in the column group header. Note that column groups are exported by default, this option will not work with skipColumnGroupHeaders=true.
|
The following example shows Excel customisations where the exported document has the following:
- Group headers with the prefix
group header: - Headers with the prefix
header:
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
ColumnApiModule,
CsvExportModule,
ExcelExportParams,
GridApi,
GridOptions,
GridReadyEvent,
ModuleRegistry,
NumberFilterModule,
ProcessGroupHeaderForExportParams,
ProcessHeaderForExportParams,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ContextMenuModule,
ExcelExportModule,
RowGroupingModule,
SetFilterModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
const modules = [
ColumnApiModule,
NumberFilterModule,
ClientSideRowModelModule,
CsvExportModule,
ExcelExportModule,
ColumnMenuModule,
ContextMenuModule,
RowGroupingModule,
SetFilterModule,
];
const getParams: () => ExcelExportParams = () => ({
processHeaderCallback(params: ProcessHeaderForExportParams): string {
return `header: ${params.api.getDisplayNameForColumn(params.column, null)}`;
},
processGroupHeaderCallback(
params: ProcessGroupHeaderForExportParams,
): string {
return `group header: ${params.api.getDisplayNameForColumnGroup(params.columnGroup, null)}`;
},
});
const GridExample = () => {
const gridRef = useRef<AgGridReact<IOlympicData>>(null);
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<IOlympicData[]>();
const [columnDefs, setColumnDefs] = useState<(ColDef | ColGroupDef)[]>([
{
headerName: "Athlete details",
children: [
{ field: "athlete", minWidth: 200 },
{ field: "country", minWidth: 150 },
{ field: "sport", minWidth: 150 },
],
},
{
headerName: "Medal results",
children: [{ field: "gold" }, { field: "silver" }, { field: "bronze" }],
},
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
filter: true,
minWidth: 100,
flex: 1,
};
}, []);
const popupParent = useMemo<HTMLElement | null>(() => {
return document.body;
}, []);
const onGridReady = useCallback((params: GridReadyEvent) => {
fetch("https://www.ag-grid.com/example-assets/small-olympic-winners.json")
.then((resp) => resp.json())
.then((data: IOlympicData[]) =>
setRowData(data.filter((rec: any) => rec.country != null)),
);
}, []);
const onBtExport = useCallback(() => {
gridRef.current!.api.exportDataAsExcel(getParams());
}, [getParams]);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div className="container">
<div>
<button
onClick={onBtExport}
style={{ margin: "5px 0px", fontWeight: "bold" }}
>
Export to Excel
</button>
</div>
<div className="grid-wrapper">
<div style={gridStyle}>
<AgGridReact<IOlympicData>
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
popupParent={popupParent}
onGridReady={onGridReady}
/>
</div>
</div>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
.details > label {
margin-bottom: 10px;
}
.details > label:first-of-type {
margin-top: 10px;
}
.details > label:last-of-type {
margin-bottom: 0;
}
.option {
display: block;
margin: 5px 10px 5px 0;
}
.grid-wrapper {
display: flex;
flex: 1 1 0px;
}
.grid-wrapper > div {
width: 100%;
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.columns {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
}
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} Custom Metadata Copy Link
Use customMetadata to write custom document properties to the exported file. The values are added as metadata to the Excel file and serialised as strings.
This is useful for attaching internal identifiers, workflow hints, or metadata consumed by downstream systems.
Use cases for custom metadata may include:
- Internal workflow tagging (for example, adding
ExportIDorGeneratedByfor tracking in automation scripts). - Integration with document management systems (for example, embedding
ContractTypeorExpirationDatefor indexing in SharePoint or similar tools). - Integration with third-party analytics tools (for example, passing
CampaignIDfor BI dashboard automation).
gridApi.exportDataAsExcel({
customMetadata: {
ExportID: 'EXP-2026-001',
ExpirationDate: '2025-01-01T12:00:00Z',
Disclaimer: 'Preliminary data; subject to audit',
},
});Properties available on the ExcelExportParams interface.
Custom metadata to write to docProps/custom.xml in the exported file. Values are serialised as strings.
|
The Grid does not interpret these values or apply labels; it only writes the custom properties provided in the customMetadata parameter. This feature does not replace or integrate with officially endorsed labelling systems, such as Microsoft Purview Sensitivity Labels, which require specific SDKs or APIs for enforcement, encryption, and compliance.
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
CsvExportModule,
ExcelExportParams,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
TextFilterModule,
enableDevValidations,
} from "ag-grid-community";
import { ExcelExportModule } from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
const modules = [
ClientSideRowModelModule,
CsvExportModule,
ExcelExportModule,
NumberFilterModule,
TextFilterModule,
];
interface ReportRow {
department: string;
reportId: string;
owner: string;
cost: number;
}
const customMetadata = {
ExportID: "EXP-2026-001",
ExpirationDate: "2025-01-01T12:00:00Z",
Disclaimer: "Preliminary data; subject to audit",
};
const GridExample = () => {
const gridRef = useRef<AgGridReact<ReportRow>>(null);
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<ReportRow[]>([
{
department: "Security",
reportId: "RPT-001",
owner: "Morgan",
cost: 1200,
},
{ department: "Finance", reportId: "RPT-014", owner: "Avery", cost: 5400 },
{
department: "Operations",
reportId: "RPT-082",
owner: "Jordan",
cost: 3100,
},
{ department: "Legal", reportId: "RPT-109", owner: "Taylor", cost: 2700 },
]);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "department", minWidth: 160 },
{ field: "reportId", minWidth: 140 },
{ field: "owner", minWidth: 140 },
{ field: "cost", filter: "agNumberColumnFilter", minWidth: 120 },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
filter: true,
flex: 1,
minWidth: 120,
};
}, []);
const defaultExcelExportParams = useMemo<ExcelExportParams>(() => {
return {
customMetadata: customMetadata,
};
}, []);
const onBtExport = useCallback(() => {
gridRef.current!.api.exportDataAsExcel();
}, []);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div className="container">
<div>
<button
onClick={onBtExport}
style={{ margin: "5px 0px", fontWeight: "bold" }}
>
Export to Excel
</button>
</div>
<div className="grid-wrapper">
<div style={gridStyle}>
<AgGridReact<ReportRow>
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
defaultExcelExportParams={defaultExcelExportParams}
/>
</div>
</div>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
.details > label {
margin-bottom: 10px;
}
.details > label:first-of-type {
margin-top: 10px;
}
.details > label:last-of-type {
margin-bottom: 0;
}
.option {
display: block;
margin: 5px 10px 5px 0;
}
.grid-wrapper {
display: flex;
flex: 1 1 0px;
}
.grid-wrapper > div {
width: 100%;
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.columns {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
}