---
product: "AG Grid"
title: "PDF Export - Master Detail"
description: "By default, exporting a Master Detail grid includes the master rows but not their detail grids. Use getCustomContentBelowRow to return a PDF representation of the detail data that should be inserted below each master row."
enterprise: true
framework: react
version: "36.2.0"
related:
    - title: "Styles"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-styles/"
    - title: "Languages"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-languages/"
    - title: "Extra Content"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-extra-content/"
    - title: "Customising Content"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-customising-content/"
    - title: "Images"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-images/"
    - title: "Watermarks"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-watermarks/"
    - title: "Rows"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-rows/"
    - title: "Columns"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-columns/"
    - title: "Hyperlinks"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-hyperlinks/"
    - title: "Page Setup"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-page-setup/"
    - title: "API Reference"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/pdf-export-api/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# PDF Export - Master Detail

By default, exporting a Master Detail grid includes the master rows but not their detail grids. Use `getCustomContentBelowRow` to return a PDF representation of the detail data that should be inserted below each master row.

## Exporting Master And Detail Rows

`getCustomContentBelowRow` receives the master row node and returns `PdfCell[][]`. Build these rows from the detail data stored on the master record:

```jsx
const defaultPdfExportParams = {
    getCustomContentBelowRow: (params) => {
        const records = params.node.data.callRecords;

        return [
            [
                { data: { value: 'Call ID' } },
                { data: { value: 'Direction' } },
                { data: { value: 'Number' } },
                { data: { value: 'Duration / Switch Code' } },
            ],
            ...records.map((record) => [
                { data: { value: String(record.callId) } },
                { data: { value: record.direction } },
                { data: { value: record.number } },
                { data: { value: `${record.duration}s / ${record.switchCode}` } },
            ]),
        ];
    },
};

<AgGridReact defaultPdfExportParams={defaultPdfExportParams} />
```

This approach does not create or export a separate detail-grid instance. It works whether the detail row is expanded or collapsed and avoids creating every detail grid during export.

Detail-grid behaviour is not applied automatically. If `detailGridOptions` contains Value Getters, Value Formatters, sorting or filtering that should be represented in the PDF, apply the equivalent logic while building the custom rows.

> **Note**
>
> Custom content uses the master table's exported column layout. Build a compact detail representation that fits the number and widths of the exported master columns.

The example below exports a heading, column headers and all call records below each master account row. The duration formatting used by the detail grid is reproduced when the PDF content is created.

#### PDF Export - Master Detail

```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,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  PdfCell,
  PdfCellStyle,
  PdfExportParams,
  ProcessRowGroupForExportParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  MasterDetailModule,
  PdfExportModule,
} from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  MasterDetailModule,
  PdfExportModule,
  ColumnMenuModule,
  ContextMenuModule,
];

const detailHeadingStyle: PdfCellStyle = {
  backgroundColor: "#d9eaf7",
  color: "#19486a",
  fontWeight: "bold",
  padding: 6,
};

const detailHeaderStyle: PdfCellStyle = {
  backgroundColor: "#eef4f8",
  color: "#243746",
  fontWeight: "bold",
  padding: 5,
};

const getDetailRows: (
  params: ProcessRowGroupForExportParams<IAccount>,
) => PdfCell[][] = (params: ProcessRowGroupForExportParams<IAccount>) => {
  const account = params.node.data;
  if (!account) {
    return [];
  }
  const rows: PdfCell[][] = [
    [
      {
        data: { value: `Calls for ${account.name}` },
        mergeAcross: 3,
        style: detailHeadingStyle,
      },
    ],
    [
      { data: { value: "Call ID" }, style: detailHeaderStyle },
      { data: { value: "Direction" }, style: detailHeaderStyle },
      { data: { value: "Number" }, style: detailHeaderStyle },
      { data: { value: "Duration / Switch Code" }, style: detailHeaderStyle },
    ],
  ];
  for (const record of account.callRecords) {
    rows.push([
      { data: { value: String(record.callId) } },
      { data: { value: record.direction } },
      { data: { value: record.number } },
      { data: { value: `${record.duration}s / ${record.switchCode}` } },
    ]);
  }
  return rows;
};

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IAccount>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "name", cellRenderer: "agGroupCellRenderer", minWidth: 180 },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: (params) => `${params.value}m` },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 110,
    };
  }, []);
  const detailCellRendererParams = useMemo(() => {
    return {
      detailGridOptions: {
        columnDefs: [
          { field: "callId" },
          { field: "direction" },
          { field: "number", minWidth: 150 },
          { field: "duration", valueFormatter: (params) => `${params.value}s` },
          { field: "switchCode", minWidth: 150 },
        ],
        defaultColDef: {
          flex: 1,
        },
      },
      getDetailRowData: (params) => {
        params.successCallback(params.data.callRecords);
      },
    } as IDetailCellRendererParams<IAccount, ICallRecord>;
  }, []);
  const defaultPdfExportParams = useMemo<PdfExportParams>(() => {
    return {
      columnWidth: "auto",
      getCustomContentBelowRow: getDetailRows,
    };
  }, []);

  const { data, loading } = useFetchJson<IAccount>(
    "https://www.ag-grid.com/example-assets/master-detail-data.json",
    3,
  );

  const onBtExport = useCallback(() => {
    gridRef.current!.api.exportDataAsPdf();
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="controls">
            <button onClick={onBtExport}>Export to PDF</button>
          </div>

          <div style={gridStyle}>
            <AgGridReact<IAccount>
              ref={gridRef}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              masterDetail={true}
              detailCellRendererParams={detailCellRendererParams}
              defaultPdfExportParams={defaultPdfExportParams}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: PDF Export - Master Detail](https://www.ag-grid.com/archive/36.2.0/examples/pdf-export-master-detail/pdf-export-master-detail/reactFunctionalTs/)

## API

### Export Options

See below the functions on the `PdfExportParams` interface to customise exported grid values.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getCustomContentBelowRow` | `Function` |  |  |  |

### PdfCell

Properties available on the `PdfCell` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `data` | `PdfCellData` |  |  |  |
| `mergeAcross` | `number` |  |  |  |
| `style` | `PdfCellStyle` |  |  |  |

### PdfCellData

Properties available on the `PdfCellData` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `value` | `string \| null` |  |  |  |
| `hyperlink` | `string` |  |  |  |
| `image` | `PdfImage` |  |  |  |

### ProcessRowGroupForExportParams

Properties available on the `ProcessRowGroupForExportParams&lt;TData = any, TContext = any&gt;` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `node` | `IRowNode` |  |  |  |
| `column` | `Column` |  |  |  |
| `api` | `GridApi` |  |  |  |
| `context` | `TContext` |  |  |  |
