---
title: "Master / Detail - Detail Height"
enterprise: true
framework: react
version: "36.1.0"
---

# Master / Detail - Detail Height

This section shows how the detail height can be customised to suit application requirements.

## Detail Height Options

The default height of each detail section (ie the row containing the Detail Grid in the master) is fixed at `300px`. The height does not change based on how much data there is to display in the detail section.

To change the height of the details section from the default you have the following options:

- [Fixed Height](https://www.ag-grid.com/react-data-grid/master-detail-height/#fixed-height): a custom fixed height can be provided for all detail sections instead of the default `300px`.
- [Auto Height](https://www.ag-grid.com/react-data-grid/master-detail-height/#auto-height): detail sections can auto-size to fit based off the contents.
- [Dynamic Height](https://www.ag-grid.com/react-data-grid/master-detail-height/#dynamic-height): different heights can be provided for each detail section.

## Fixed Height

Use the grid property `detailRowHeight` to set a fixed height for each detail row.

```jsx
// statically fix row height for all detail grids
const detailRowHeight = 200;

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

The following example sets a fixed row height for all detail rows.

#### Fixed Detail Row Height

```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 {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  RowApiModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  MasterDetailModule,
} from "ag-grid-enterprise";
import { IAccount } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  RowApiModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  MasterDetailModule,
  ColumnMenuModule,
  ContextMenuModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    // group cell renderer needed for expand / collapse icons
    { field: "name", cellRenderer: "agGroupCellRenderer" },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const detailCellRendererParams = useMemo(() => {
    return {
      detailGridOptions: {
        columnDefs: [
          { field: "callId" },
          { field: "direction" },
          { field: "number", minWidth: 150 },
          { field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
          { field: "switchCode", minWidth: 150 },
        ],
        defaultColDef: {
          flex: 1,
        },
      },
      getDetailRowData: (params) => {
        params.successCallback(params.data.callRecords);
      },
    } as IDetailCellRendererParams<IAccount, ICallRecord>;
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    // arbitrarily expand a row for presentational purposes
    setTimeout(() => {
      params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
    }, 0);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IAccount>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            masterDetail={true}
            detailRowHeight={200}
            detailCellRendererParams={detailCellRendererParams}
            alwaysShowVerticalScroll={true}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Fixed Detail Row Height](https://www.ag-grid.com/examples/master-detail-height/fixed-detail-row-height/reactFunctionalTs)

## Auto Height

Set grid property `detailRowAutoHeight=true` to have the detail grid dynamically change its height to fit its rows.

```jsx
// dynamically set row height for all detail grids
const detailRowAutoHeight = true;

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

#### Auto Height

```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 {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  RowApiModule,
  enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [RowApiModule, ClientSideRowModelModule, MasterDetailModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    // group cell renderer needed for expand / collapse icons
    { field: "name", cellRenderer: "agGroupCellRenderer" },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const detailCellRendererParams = useMemo(() => {
    return {
      detailGridOptions: {
        columnDefs: [
          { field: "callId" },
          { field: "direction" },
          { field: "number", minWidth: 150 },
          { field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
          { field: "switchCode", minWidth: 150 },
        ],
        defaultColDef: {
          flex: 1,
        },
      },
      getDetailRowData: (params) => {
        params.successCallback(params.data.callRecords);
      },
    } as IDetailCellRendererParams<IAccount, ICallRecord>;
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    // arbitrarily expand a row for presentational purposes
    setTimeout(() => {
      params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
    }, 0);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IAccount>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            masterDetail={true}
            detailRowAutoHeight={true}
            detailCellRendererParams={detailCellRendererParams}
            alwaysShowVerticalScroll={true}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Auto Height](https://www.ag-grid.com/examples/master-detail-height/auto-height/reactFunctionalTs)

Note that when using Auto Height, the Detail Grid will have a minimum height of 150px for the rows section. See [Min Height with Auto Height](https://www.ag-grid.com/react-data-grid/grid-size/#min-height-with-auto-height) for more information on how to change this.

> **Note**
>
> When using Auto Height feature, the Detail Grid will render all of its rows all the time. [Row Virtualisation](https://www.ag-grid.com/react-data-grid/dom-virtualisation/) will not happen. This means if the Detail Grid has many rows, it could slow down your application and could result in stalling the browser.
>
> Do not use Auto Height if you have many rows (eg 100+) in the Detail Grids. To know if this is a concern for your grid and dataset, try it out and check the performance.

### Auto Height with Custom Detail

If you are providing your own [Detail Cell Renderer](https://www.ag-grid.com/react-data-grid/master-detail-custom-detail/), set `detailRowAutoHeight: true` in the master-level gridOptions and ensure the content nested inside the detail cell renderer component sets a height value.

Here is an example of Auto Height being used with a Custom Detail Cell Renderer:

#### Auto Height with Custom 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 {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  RowApiModule,
  enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [RowApiModule, ClientSideRowModelModule, MasterDetailModule];

export class DetailCellRenderer {
  eGui: HTMLDivElement | undefined;

  init() {
    this.eGui = document.createElement("div");
    //additional content shown in detail
    const panel = document.createElement("div");

    // Notice: the height is set
    panel.style =
      "height:100px; background-color:lightblue; padding: 15px; font-weight: bold; ";
    panel.innerText = "Optional element content";

    // button to toggle optional content visibility
    const btn = document.createElement("button");
    btn.innerText = "Show Optional Element";

    btn.style = "margin:10px";
    btn.addEventListener("click", function (p: any) {
      //add your own condition here based on application logic - this only checks the number of children shown
      if (p.target.parentElement.children.length === 1) {
        p.target.parentElement.appendChild(panel);
        p.target.innerText = "Hide Optional Element";
      } else {
        p.target.parentElement.removeChild(panel);
        p.target.innerText = "Show Optional Element";
      }
    });

    this.eGui.appendChild(btn);
  }

  getGui() {
    return this.eGui;
  }

  refresh() {
    return false;
  }
}

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    // group cell renderer needed for expand / collapse icons
    { field: "name", cellRenderer: "agGroupCellRenderer" },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const detailCellRendererParams = useMemo(() => {
    return {
      detailGridOptions: {
        columnDefs: [
          { field: "callId" },
          { field: "direction" },
          { field: "number", minWidth: 150 },
          { field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
          { field: "switchCode", minWidth: 150 },
        ],
        defaultColDef: {
          flex: 1,
        },
      },
      getDetailRowData: (params) => {
        params.successCallback(params.data.callRecords);
      },
    } as IDetailCellRendererParams<IAccount, ICallRecord>;
  }, []);
  const detailCellRenderer = useCallback(DetailCellRenderer, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    // arbitrarily expand a row for presentational purposes
    setTimeout(() => {
      params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
    }, 0);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IAccount>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            masterDetail={true}
            detailRowAutoHeight={true}
            detailCellRendererParams={detailCellRendererParams}
            detailCellRenderer={detailCellRenderer}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Auto Height with Custom Detail](https://www.ag-grid.com/examples/master-detail-height/custom-detail-auto-height/reactFunctionalTs)

## Dynamic Height

Use the callback `getRowHeight(params)` to set height for each row individually. This is a specific use of the callback that is explained in more detail in [Get Row Height](https://www.ag-grid.com/react-data-grid/row-height/#getrowheight-callback)

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getRowHeight` | `GetRowHeight` |  |  | Callback version of property `rowHeight` to set height for each row individually. Function should return a positive number of pixels, or return `null`/`undefined` to use the default row height. |

Note that this callback gets called for **all rows** in the Master Grid, not just rows containing Detail Grids. If you do not want to set row heights explicitly for other rows simply return `undefined / null` and the grid will ignore the result for that particular row.

```jsx
// dynamically assigning detail row height
const getRowHeight = params => {
    const isDetailRow = params.node.detail;
    // for all rows that are not detail rows, return nothing
    if (!isDetailRow) { return undefined; }

    // otherwise return height based on number of rows in detail grid
    const detailPanelHeight = params.data.children.length * 50;
    return detailPanelHeight;
};

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

The following example demonstrates dynamic detail row heights:

#### Dynamic Detail Row Height

```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 {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GetRowHeight,
  GridApi,
  GridOptions,
  IDetailCellRendererParams,
  ModuleRegistry,
  RenderApiModule,
  RowApiModule,
  RowHeightParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  MasterDetailModule,
} from "ag-grid-enterprise";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  RenderApiModule,
  RowApiModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  MasterDetailModule,
  ColumnMenuModule,
  ContextMenuModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    // group cell renderer needed for expand / collapse icons
    { field: "name", cellRenderer: "agGroupCellRenderer" },
    { field: "account" },
    { field: "calls" },
    { field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const detailCellRendererParams = useMemo<any>(() => {
    return {
      detailGridOptions: {
        columnDefs: [
          { field: "callId" },
          { field: "direction" },
          { field: "number" },
          { field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
          { field: "switchCode" },
        ],
        defaultColDef: {
          flex: 1,
        },
        onGridReady: (params) => {
          // using auto height to fit the height of the the detail grid
          params.api.setGridOption("domLayout", "autoHeight");
        },
      },
      getDetailRowData: (params) => {
        params.successCallback(params.data.callRecords);
      },
    } as IDetailCellRendererParams<IAccount, ICallRecord>;
  }, []);
  const getRowHeight = useCallback((params: RowHeightParams) => {
    if (params.node && params.node.detail) {
      const offset = 80;
      const allDetailRowHeight =
        params.data.callRecords.length *
        params.api.getSizesForCurrentTheme().rowHeight;
      const gridSizes = params.api.getSizesForCurrentTheme();
      return (
        allDetailRowHeight +
        ((gridSizes && gridSizes.headerHeight) || 0) +
        offset
      );
    }
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    // arbitrarily expand a row for presentational purposes
    setTimeout(() => {
      params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
    }, 0);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            masterDetail={true}
            detailCellRendererParams={detailCellRendererParams}
            getRowHeight={getRowHeight}
            alwaysShowVerticalScroll={true}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Dynamic Detail Row Height](https://www.ag-grid.com/examples/master-detail-height/dynamic-detail-row-height/reactFunctionalTs)
