---
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: javascript
version: "36.2.0"
related:
    - title: "Styles"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-styles/"
    - title: "Languages"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-languages/"
    - title: "Extra Content"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-extra-content/"
    - title: "Customising Content"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-customising-content/"
    - title: "Images"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-images/"
    - title: "Watermarks"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-watermarks/"
    - title: "Rows"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-rows/"
    - title: "Columns"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-columns/"
    - title: "Hyperlinks"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-hyperlinks/"
    - title: "Page Setup"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/pdf-export-page-setup/"
    - title: "API Reference"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-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:

```js
const gridOptions = {
    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}` } },
                ]),
            ];
        },
    },

    // other grid options ...
}
```

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

```ts
import {
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  PdfCell,
  PdfCellStyle,
  ProcessRowGroupForExportParams,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  MasterDetailModule,
  PdfExportModule,
} from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";

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

ModuleRegistry.registerModules([
  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,
};

function getDetailRows(
  params: ProcessRowGroupForExportParams<IAccount>,
): PdfCell[][] {
  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;
}

let gridApi: GridApi<IAccount>;

const gridOptions: GridOptions<IAccount> = {
  columnDefs: [
    { field: "name", cellRenderer: "agGroupCellRenderer", minWidth: 180 },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: (params) => `${params.value}m` },
  ],
  defaultColDef: {
    flex: 1,
    minWidth: 110,
  },
  masterDetail: true,
  detailCellRendererParams: {
    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>,
  defaultPdfExportParams: {
    columnWidth: "auto",
    getCustomContentBelowRow: getDetailRows,
  },
};

function onBtExport() {
  gridApi.exportDataAsPdf();
}

gridApi = createGrid(
  document.querySelector<HTMLElement>("#myGrid")!,
  gridOptions,
);

fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
  .then((response) => response.json())
  .then((data: IAccount[]) => {
    gridApi.setGridOption("rowData", data.slice(0, 3));
  });

if (typeof window !== "undefined") {
  // Attach external event handlers to window so they can be called from index.html
  (<any>window).onBtExport = onBtExport;
}
```

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

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