---
title: "Excel Export - Customising Content"
enterprise: true
framework: react
version: "36.1.0"
---

# Excel Export - Customising Content

## Customising Cell and Row Group values

By default, the values exported to Excel will be formatted via the [Using the Value Formatter for Export](https://www.ag-grid.com/react-data-grid/value-formatters/#formatting-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`.

```jsx
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.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `processCellCallback` | `Function` |  |  | 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. |
| `processRowGroupCallback` | `Function` |  |  | 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 are `undefined`, in which case they are empty

> **Note**
>
> When using row grouping while [hiding open parents](https://www.ag-grid.com/react-data-grid/grouping-multiple-group-columns/#hiding-expanded-parent-rows) (`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.

#### Excel Export - Customising Row Groups

```tsx
"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") {
  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>,
);
```

[Live example: Excel Export - Customising Row Groups](https://www.ag-grid.com/examples/excel-export-customising-content/excel-export-customising-row-groups/reactFunctionalTs)

## Customising Column Headers and Group Header Values

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`.

```jsx
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.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `processHeaderCallback` | `Function` |  |  | A callback function invoked once per column. Return a string to be displayed in the column header. |
| `processGroupHeaderCallback` | `Function` |  |  | 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: `

#### Excel Export - Customising Column Group Headers

```tsx
"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") {
  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>,
);
```

[Live example: Excel Export - Customising Column Group Headers](https://www.ag-grid.com/examples/excel-export-customising-content/excel-export-customising-column-group-headers/reactFunctionalTs)

## Custom Metadata

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 `ExportID` or `GeneratedBy` for tracking in automation scripts).
- Integration with document management systems (for example, embedding `ContractType` or `ExpirationDate` for indexing in SharePoint or similar tools).
- Integration with third-party analytics tools (for example, passing `CampaignID` for BI dashboard automation).

```jsx
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.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `customMetadata` | `ExcelCustomMetadata` |  |  | Custom metadata to write to `docProps/custom.xml` in the exported file. Values are serialised as strings. |

> **Note**
>
> 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.

#### Excel Export - Custom Metadata

```tsx
"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") {
  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>,
);
```

[Live example: Excel Export - Custom Metadata](https://www.ag-grid.com/examples/excel-export-customising-content/excel-export-customising-custom-metadata/reactFunctionalTs)
