It is possible to nest Master / Detail grids. There is no special configuration required to do this, you just configure another Detail Grid to also act as a Master Grid.
The following snippet illustrates how to achieve nesting by configuring Detail Grids to also act as Master Grids.
// Level 3 (bottom level), Detail Grid only, no Master / Detail configuration
const gridOptionsLevel3 = {
...
}
// Level 2, configured to be a Master Grid and use Level 3 grid as Detail Grid,
const gridOptionsLevel2 = {
masterDetail: true,
detailCellRendererParams: {
detailGridOptions: gridOptionsLevel3,
getDetailRowData: function (params) {
...
}
}
...
}
// Level 1, configured to be a Master Grid and use Level 2 grid as Detail Grid,
const gridOptionsLevel1 = {
masterDetail: true,
detailCellRendererParams: {
detailGridOptions: gridOptionsLevel2,
getDetailRowData: function (params) {
...
}
}
...
}Below shows a simple Master Detail setup with two levels of Master Detail. The example is kept short (few rows and columns) so as to focus on the nesting.
Example Copy Link
"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,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
const modules = [
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
];
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<any[]>([
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
]);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "a1", cellRenderer: "agGroupCellRenderer" },
{ field: "b1" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
flex: 1,
};
}, []);
const detailCellRendererParams = useMemo<any>(() => {
return {
// level 2 grid options
detailGridOptions: {
columnDefs: [
{ field: "a2", cellRenderer: "agGroupCellRenderer" },
{ field: "b2" },
],
defaultColDef: {
flex: 1,
},
groupDefaultExpanded: 1,
masterDetail: true,
detailRowHeight: 240,
detailCellRendererParams: {
// level 3 grid options
detailGridOptions: {
columnDefs: [
{ field: "a3", cellRenderer: "agGroupCellRenderer" },
{ field: "b3" },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams,
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams;
}, []);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
groupDefaultExpanded={1}
masterDetail={true}
detailCellRendererParams={detailCellRendererParams}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
Example: Auto Height Copy Link
The next example is identical to the previous except all the Detail Grids have property detailRowAutoHeight=true. Notice that this removes all vertical scrolls from all the Detail Grids, leaving just the main Master Grid with a vertical scroll.
"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,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
const modules = [
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
];
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<any[]>([
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
]);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "a1", cellRenderer: "agGroupCellRenderer" },
{ field: "b1" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
flex: 1,
};
}, []);
const detailCellRendererParams = useMemo<any>(() => {
return {
// level 2 grid options
detailGridOptions: {
columnDefs: [
{ field: "a2", cellRenderer: "agGroupCellRenderer" },
{ field: "b2" },
],
defaultColDef: {
flex: 1,
},
groupDefaultExpanded: 1,
masterDetail: true,
detailRowHeight: 240,
detailRowAutoHeight: true,
detailCellRendererParams: {
// level 3 grid options
detailGridOptions: {
columnDefs: [
{ field: "a3", cellRenderer: "agGroupCellRenderer" },
{ field: "b3" },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams,
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams;
}, []);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
groupDefaultExpanded={1}
masterDetail={true}
detailRowAutoHeight={true}
detailCellRendererParams={detailCellRendererParams}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);