Enterprise Feature : Master Detail requires ag-grid-enterprise and a valid license key.
Master Detail allows you to embed full grid instances within expandable row details, creating hierarchical data displays with independent grids for each master row.
Installation
Install Package
npm install ag-grid-enterprise
Import Module
import { ModuleRegistry } from 'ag-grid-community' ;
import { MasterDetailModule } from 'ag-grid-enterprise' ;
ModuleRegistry . registerModules ([ MasterDetailModule ]);
Set License Key
import { LicenseManager } from 'ag-grid-enterprise' ;
LicenseManager . setLicenseKey ( 'YOUR_LICENSE_KEY' );
Source: /packages/ag-grid-enterprise/src/masterDetail/masterDetailModule.ts:40-44
Basic Master Detail
Enable Master Detail with a simple configuration:
import { GridOptions , IDetailCellRendererParams } from 'ag-grid-community' ;
const gridOptions : GridOptions = {
masterDetail: true ,
columnDefs: [
{ field: 'name' , cellRenderer: 'agGroupCellRenderer' },
{ field: 'account' },
{ field: 'calls' }
],
rowData: [
{
name: 'Customer A' ,
account: 'ACC-001' ,
calls: 10 ,
callRecords: [
{ date: '2024-01-01' , duration: 300 , outcome: 'Success' },
{ date: '2024-01-05' , duration: 450 , outcome: 'Failed' }
]
}
],
// Detail cell renderer parameters
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: 'date' },
{ field: 'duration' },
{ field: 'outcome' }
]
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords );
}
} as IDetailCellRendererParams
};
Configuration
Enable Master Detail
Basic grid options for Master Detail:
const gridOptions : GridOptions = {
// Enable master detail
masterDetail: true ,
// Keep detail rows on data update
keepDetailRows: true ,
// Keep detail row count in sync
keepDetailRowsCount: 10 ,
// Embed full width rows
embedFullWidthRows: true ,
// Detail row height
detailRowHeight: 300 ,
// Auto height for detail rows
detailRowAutoHeight: true
};
Detail Cell Renderer Parameters
Configure the detail grid:
import { IDetailCellRendererParams } from 'ag-grid-community' ;
const detailCellRendererParams : IDetailCellRendererParams = {
// Detail grid options
detailGridOptions: {
columnDefs: [
{ field: 'callId' , headerName: 'Call ID' },
{ field: 'date' , headerName: 'Date' },
{ field: 'duration' , headerName: 'Duration (sec)' },
{ field: 'outcome' , headerName: 'Outcome' }
],
defaultColDef: {
flex: 1 ,
sortable: true ,
filter: true
},
rowSelection: 'multiple'
},
// Provide data for detail grid
getDetailRowData : ( params ) => {
// params.data contains the master row data
params . successCallback ( params . data . callRecords );
},
// Template for loading state
template: '<div style="padding: 20px;">Loading...</div>' ,
// Refresh strategy
refreshStrategy: 'rows' // 'rows' | 'everything'
};
Async Data Loading
Load detail data asynchronously:
const detailCellRendererParams : IDetailCellRendererParams = {
detailGridOptions: {
columnDefs: detailColumnDefs
},
getDetailRowData : async ( params ) => {
try {
// Fetch data from API
const response = await fetch (
`/api/call-records/ ${ params . data . accountId } `
);
const data = await response . json ();
// Provide data to detail grid
params . successCallback ( data );
} catch ( error ) {
console . error ( 'Error loading detail data:' , error );
params . successCallback ([]);
}
}
};
Master Row Configuration
Group Cell Renderer
The master row needs a group cell renderer to show expand/collapse:
const columnDefs : ColDef [] = [
{
field: 'name' ,
cellRenderer: 'agGroupCellRenderer' ,
cellRendererParams: {
// Customize expand icon
innerRenderer : ( params ) => {
return params . data . name ;
},
// Suppress row count
suppressCount: true ,
// Add checkbox
checkbox: true
}
},
{ field: 'account' },
{ field: 'calls' }
];
Conditional Detail Rows
Show detail rows only for certain master rows:
const gridOptions : GridOptions = {
masterDetail: true ,
// Determine if row has detail
isRowMaster : ( dataItem ) => {
return dataItem . callRecords && dataItem . callRecords . length > 0 ;
},
detailCellRendererParams: {
detailGridOptions: { /*...*/ },
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords || []);
}
}
};
Detail Grid API
Access and control detail grids programmatically:
Access Detail Grid Info
import { GridApi , DetailGridInfo } from 'ag-grid-community' ;
const api : GridApi = gridRef . current . api ;
// Get detail grid info for a specific master row
const detailInfo = api . getDetailGridInfo ( 'master-row-id' );
if ( detailInfo ) {
console . log ( 'Detail Grid API:' , detailInfo . api );
console . log ( 'Detail Column API:' , detailInfo . columnApi );
// Use detail grid API
detailInfo . api . selectAll ();
detailInfo . api . exportDataAsCsv ();
}
Source: /packages/ag-grid-enterprise/src/masterDetail/masterDetailApi.ts:23-25
Store Detail Grid Reference
// Add detail grid info
api . addDetailGridInfo ( 'master-row-id' , detailGridInfo );
// Remove detail grid info
api . removeDetailGridInfo ( 'master-row-id' );
// Iterate all detail grids
api . forEachDetailGridInfo (( detailInfo , index ) => {
console . log ( `Detail grid ${ index } :` , detailInfo );
// Apply operation to all detail grids
detailInfo . api . deselectAll ();
});
Sources:
addDetailGridInfo: /packages/ag-grid-enterprise/src/masterDetail/masterDetailApi.ts:11-15
removeDetailGridInfo: /packages/ag-grid-enterprise/src/masterDetail/masterDetailApi.ts:17-21
forEachDetailGridInfo: /packages/ag-grid-enterprise/src/masterDetail/masterDetailApi.ts:27-40
Advanced Features
Full-Width Detail Rows
Create custom detail renderers:
import { ICellRendererParams } from 'ag-grid-community' ;
// Custom detail renderer component
const CustomDetailRenderer = ( props : ICellRendererParams ) => {
const data = props . data ;
return (
< div style = {{ padding : '20px' , background : '#f5f5f5' }} >
< h3 > Call Details for { data . name } </ h3 >
< div >
< p > Account : { data . account }</ p >
< p > Total Calls : { data . calls }</ p >
< div style = {{ marginTop : '20px' }} >
< AgGridReact
columnDefs = { detailColumnDefs }
rowData = {data. callRecords }
domLayout = "autoHeight"
/>
</ div >
</ div >
</ div >
);
};
const gridOptions : GridOptions = {
masterDetail: true ,
detailCellRenderer: CustomDetailRenderer
};
Detail Row Auto Height
Automatically size detail rows based on content:
const gridOptions : GridOptions = {
masterDetail: true ,
detailRowAutoHeight: true ,
detailCellRendererParams: {
detailGridOptions: {
columnDefs: detailColumnDefs ,
domLayout: 'autoHeight' , // Auto-size detail grid
pagination: false
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords );
}
}
};
Nested Master Detail
Create multiple levels of detail grids:
const detailCellRendererParams : IDetailCellRendererParams = {
detailGridOptions: {
columnDefs: [
{ field: 'region' , cellRenderer: 'agGroupCellRenderer' },
{ field: 'sales' }
],
masterDetail: true , // Enable master detail in detail grid
detailCellRendererParams: {
// Nested detail configuration
detailGridOptions: {
columnDefs: [
{ field: 'product' },
{ field: 'quantity' },
{ field: 'price' }
]
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . products );
}
}
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . regions );
}
};
Detail Grid Events
Handle events from detail grids:
const detailCellRendererParams : IDetailCellRendererParams = {
detailGridOptions: {
columnDefs: detailColumnDefs ,
onGridReady : ( params ) => {
console . log ( 'Detail grid ready:' , params );
// Store detail grid API reference
params . api . sizeColumnsToFit ();
},
onRowClicked : ( event ) => {
console . log ( 'Detail row clicked:' , event . data );
},
onSelectionChanged : ( event ) => {
const selectedRows = event . api . getSelectedRows ();
console . log ( 'Detail selection changed:' , selectedRows );
}
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords );
}
};
Refresh Detail Grids
Refresh detail grids when master data changes:
const gridOptions : GridOptions = {
masterDetail: true ,
detailCellRendererParams: {
refreshStrategy: 'rows' , // Refresh only changed rows
detailGridOptions: { /*...*/ },
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords );
}
},
onRowDataUpdated : ( event ) => {
// Optionally refresh all detail grids
event . api . forEachDetailGridInfo (( detailInfo ) => {
detailInfo . api . refreshCells ({ force: true });
});
}
};
Lazy Loading Use getDetailRowData with async loading to fetch data on demand
Keep Detail Rows Count Set keepDetailRowsCount to limit the number of cached detail grids
Destroy Unused Details Don’t use keepDetailRows: true for large datasets
Virtual Scrolling Enable virtual scrolling in detail grids for large row counts
Optimize Detail Grid Configuration
const detailCellRendererParams : IDetailCellRendererParams = {
detailGridOptions: {
columnDefs: detailColumnDefs ,
// Performance settings for detail grid
rowBuffer: 10 ,
suppressRowTransform: true ,
suppressColumnVirtualisation: false ,
// Debounce events
debounceVerticalScrollbar: true ,
// Pagination for large detail datasets
pagination: true ,
paginationPageSize: 20
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . callRecords );
}
};
const gridOptions : GridOptions = {
masterDetail: true ,
keepDetailRowsCount: 5 , // Keep only 5 detail grids in memory
detailCellRendererParams
};
Common Patterns
Orders and Line Items
interface Order {
orderId : string ;
customer : string ;
orderDate : string ;
total : number ;
lineItems : LineItem [];
}
interface LineItem {
product : string ;
quantity : number ;
price : number ;
subtotal : number ;
}
const gridOptions : GridOptions < Order > = {
masterDetail: true ,
columnDefs: [
{ field: 'orderId' , cellRenderer: 'agGroupCellRenderer' },
{ field: 'customer' },
{ field: 'orderDate' },
{ field: 'total' , valueFormatter : params => `$ ${ params . value } ` }
],
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: 'product' },
{ field: 'quantity' },
{ field: 'price' , valueFormatter : p => `$ ${ p . value } ` },
{ field: 'subtotal' , valueFormatter : p => `$ ${ p . value } ` }
],
defaultColDef: {
flex: 1
}
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . lineItems );
}
}
};
Customers and Transactions
const gridOptions : GridOptions = {
masterDetail: true ,
columnDefs: [
{ field: 'customerId' , cellRenderer: 'agGroupCellRenderer' },
{ field: 'name' },
{ field: 'accountBalance' },
{ field: 'transactionCount' }
],
isRowMaster : ( data ) => {
return data . transactionCount > 0 ;
},
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: 'date' },
{ field: 'description' },
{ field: 'amount' , cellClass : ( params ) =>
params . value < 0 ? 'negative' : 'positive' },
{ field: 'balance' }
]
},
getDetailRowData : async ( params ) => {
const response = await fetch (
`/api/transactions?customerId= ${ params . data . customerId } `
);
const transactions = await response . json ();
params . successCallback ( transactions );
}
}
};
Troubleshooting
Detail Rows Not Expanding
Check Master Detail Enabled
Ensure masterDetail: true is set in grid options
Verify Group Cell Renderer
Master column must use agGroupCellRenderer: { field : 'name' , cellRenderer : 'agGroupCellRenderer' }
Check Module Registration
Verify MasterDetailModule is registered
Verify getDetailRowData
Ensure getDetailRowData calls successCallback: getDetailRowData : ( params ) => {
params . successCallback ( params . data . details );
}
Detail Grid Not Rendering
Check that detailGridOptions includes column definitions:
detailCellRendererParams : {
detailGridOptions : {
columnDefs : [ /* Must have column defs */ ]
},
getDetailRowData : ( params ) => {
params . successCallback ( params . data . details );
}
}
Limit the number of detail grids kept in memory:
const gridOptions : GridOptions = {
masterDetail: true ,
keepDetailRowsCount: 3 , // Keep only 3 detail grids
keepDetailRows: false // Destroy detail grids when collapsed
};
Next Steps
Row Grouping Learn about row grouping for hierarchical data
Tree Data Display tree data structures
Full Width Rows Custom full-width row rendering
Excel Export Export master-detail data to Excel