Expand All

  Getting Started



  Row Models

  Themes new



  Third Party


Github stars make projects look great. Please help, donate a star, it's free.
Read about ag-Grid's Partnership with webpack.
Get informed on releases and other ag-Grid news only - never spam.
Follow on Twitter

Master / Detail

Master / Detail allows you to nest grids inside grids. The top level grid is referred to as the 'master grid'. The nested grid is referred to as the 'detail grid'. Typically the detail grid gives more information about the row in the master grid that was expanded to reveal the detail grid.

Prior to ag-Grid v14.2, Master / Detail was not a feature of ag-Grid. Instead ag-Grid provided a feature called 'flower nodes' that could be used to implement Master / Detail which required a lot of complex configuration. Flower nodes are now deprecated. We will continue to support flower nodes for backwards compatibility, however we do not recommend them for any new development and have removed them from the documentation.

To enable Master / Detail, you should set the following grid options:

  • masterDetail: Set to true to inform the grid you want to allow expanding of rows to reveal detail grids.
  • detailGridOptions: The grid options to set for the detail grid. The detail grid is a fully featured instance of ag-Grid, so any configuration can be set on the detail grid that you would set any other grid.
  • getDetailRowData: A function you implement to provide the grid with rows for display in the detail grids.

These grid options are illustrated below:

var masterGridOptions = { columnDefs: masterColumnDefs, rowData: rowData, // enable master detail masterDetail: true, // specify params for default detail cell renderer detailCellRendererParams: { // provide detail grid options detailGridOptions: detailGridOptions, // extract and supply row data for detail getDetailRowData: function(params) { params.successCallback(params.data.childRecords); } } } var detailGridOptions = { columnDefs: detailColumnDefs }

Example - Simple Master / Detail

Below shows a simple Master / Detail setup. From the example you can notice the following:

  • masterDetail - is set to true in the master grid options.
  • detailCellRendererParams - specifies the detailGridOptions to use and getDetailRowData extracts the data for the detail row.

Overriding the Default Detail Cell Renderer

The template used by default detail Cell Renderer can be overridden with a user defined template. This is a convenient way to provide custom layouts and styles to the detail rows.

There are two ways to achieve this:

  • String Template - statically overrides the template used by the grid. The same fixed template is used for each row.
  • Template Callback - called each time a detail row is shown so can dynamically provide a template based on the data.
Both methods require specifying the detailCellRendererParams.templateproperty as shown below:

// override using string template detailCellRendererParams: { template: '<div style="background-color: #edf6ff; padding: 20px; box-sizing: border-box;">' + ' <div style="height: 10%;">Call Details</div>' + ' <div ref="eDetailGrid" style="height: 90%;"></div>' + '</div>' } } // override using template callback detailCellRendererParams: { template: function (params) { var personName = params.data.name; return '<div style="height: 100%; background-color: #EDF6FF; padding: 20px; box-sizing: border-box;">' + ' <div style="height: 10%;">Name: ' + personName + '</div>' + ' <div ref="eDetailGrid" style="height: 90%;"></div>' + '</div>'; } }

The template must contain an element with attribute ref="eDetailGrid". This element is used to host the detail grid instance.

The follow examples demonstrate both approaches.

Example - Customising via String Template

This examples demonstrates a static string template which is supplied to the detailCellRendererParams.template property to customise the layout and background colour.

Example - Customising via Template Callback

A template callback function is supplied to the detailCellRendererParams.template property to customise the layout and background colour. It additionally adds the name from the master row using the data supplied via callback parameters.

Providing a custom Detail Cell Renderer

The previous section described how to override the detail template used in the default Cell Renderer, however it is also possible to provide a custom detail Cell Renderer Component. This approach provides more flexibility but is more difficult to implement as you have to provide your own customer detail cell renderer. Use this approach if you want to add additional functionality to the detail panel that cannot be done by simply changing the template.

To supply a custom detail Cell Renderer instead of using the default use: gridOptions.detailCellRenderer

The following examples demonstrate custom Cell Renderer components for the detail row with and without a grid.

Example - Custom Detail Cell Renderer with a Grid

This example demonstrates how to embeds a grid into the detail row using a custom Cell Renderer component:

Example - Custom Detail Cell Renderer with a Form

This example demonstrates a custom Cell Renderer Component that uses a form rather than a grid:

Accessing Detail Grid API

You can access the API of all detail grids via the master grid. The API for each detail grid is stored in a DetailGridInfo object that has the following properties:

interface DetailGridInfo { // id of the detail grid, the format is detail_<row-id> // where row-id is the id of the parent row. id: string; // the grid API of the detail grid api: GridApi; // the column API of the detail grid columnApi: ColumnApi; }

The DetailGridInfo is accessed via the GridApi of the master gridOptions. You can either reference a particular detail grid API by ID, or loop through all the existing detail grid API's.

// lookup a specific DetailGridInfo by id, and then call stopEditing() on it var detailGridInfo = masterGridOptions.api.getDetailGridInfo('someDetailGridId'); detailGridInfo.api.stopEditing(); // iterate over all DetailGridInfo's, and call stopEditing() on each one masterGridOptions.api.forEachDetailGridInfo(function(detailGridInfo) { console.log("detailGridInfo: ", detailGridInfo); // then e.g. call stopEditing() on that detail grid detailGridInfo.api.stopEditing(); });

The DetailGridInfo contains a reference to the underlying Grid API and Column API for each detail grid. Methods invoked on these API's will only operate on the specific detail grid.

Example - Editing Cells with Master / Detail

This example shows how to control cell editing when using Master / Detail. This examples demonstrates the following:

  • Edit Master - performs editing on a master cell using the master grid options: masterGridOptions.api.startEditingCell()
  • Stop Edit Master - iterates over each master row node using masterGridOptions.api.forEachNode and then calls masterGridOptions.api.stopEditing() on each node.
  • Edit Detail - looks up the corresponding DetailGridInfo using masterGridOptions.api.getDetailGridInfo() and then uses the grid api on that detail grid start editing: detailGrid.api.startEditingCell()
  • Stop Edit Detail - iterates over each detail grid using masterGridOptions.api.forEachDetailGridInfo() and then calls detailGridApi.api.stopEditing() on each detail grid.

Dynamically Specify Master Nodes

It certain cases it may be required to not treat all top level rows as a master rows. For instance if a master has no child records it may not be desirable to expand the master row to an empty detail.

In order to prevent this the following callback can be used on the master grid options:

masterGridOptions.isRowMaster = function (dataItem) { // return true when row data has children, false otherwise return dataItem ? dataItem.children.length > 0 : false; }

As shown above our callback function will return true when there are detail (i.e. children) records, otherwise it will return false.

Example - Dynamically Specify Master Nodes

The following example only shows detail rows when there are corresponding child records.

Nesting Master / Detail

It is possible to nest Master / Detail grids. There are no special configurations required to achieve this, you just configure another detail grid inside the first detail grid.

The following snippet illustrates how to achieve nesting via successive grid option configurations:

// Level 1 (master) var gridOptionsLevel1Master = { ... masterDetail: true, detailCellRendererParams: { detailGridOptions: gridOptionsLevel2Master, getDetailRowData: function (params) { params.successCallback(params.data.children); } } } // Level 2 (detail and master) var gridOptionsLevel2Master = { ... masterDetail: true, detailCellRendererParams: { detailGridOptions: gridOptionsLevel3Detail, getDetailRowData: function (params) { params.successCallback(params.data.children); } } } // Level 3 (detail only) var gridOptionsLevel3Detail = { ... // no master / detail configuration }

Example - Nesting Master / Detail

Below shows a contrived master detail setup to help illustrate how nesting can be achieved. The example has very little data - this is on purpose to focus on the nesting.

Detail Row Height

The height of detail rows can be configured in one of the following two ways:

  1. Use property detailRowHeight to set a fixed height for each detail row.
  2. Use callback getRowHeight() to set height for each row individually. One extra complication here is that this method is called for every row in the grid including master rows.

The following snippet compares both approaches:

// option 1 - fixed detail row height, sets height for all details rows masterGridOptions.detailRowHeight = 500; // option 2 - dynamic detail row height, dynamically sets height for all rows masterGridOptions.getRowHeight = function (params) { var isDetailRow = params.node.detail; if (isDetailRow) { var detailPanelHeight = params.data.children.length * 50; // dynamically calculate detail row height return detailPanelHeight; } else { // for all non-detail rows, return 25, the default row height return 25; } }

Note that the detail property can be used to identify detail rows.

The following examples demonstrate both approaches:

Example - Fixed Detail Row Height

The following demonstrates a fixed detail row height:

Example - Dynamic Detail Row Height

The following example demonstrates dynamic detail row heights:

Filtering and Sorting

There are no specific configurations for filtering and sorting with Master / Detail but as there are multiple grids each grid will filter and sort independently.

Example - Filtering with Sort

Below shows a simple Master / Detail setup which has filtering and sorting enabled in both master and detail grids.

Lazy Load Detail Rows

It is possible to lazy load detail row data as it becomes available. For instance an asynchronous request could be sent when expanding a master row to fetch detail records.

The following snippet illustrates this using a simple setTimeout() function to delay supplying data to the detail row after a fixed timeout.

var masterGridOptions = { detailCellRendererParams: { getDetailRowData: function (params) { // simulate delayed supply of data to the detail pane setTimeout(function () { params.successCallback(params.data.childRecords); }, 1000); } } };

Note that the key to this approach is the params.successCallback(data) function provided via the params, which can be invoked later or asynchronously once the data for the detail row is available.

Example - Lazy Load Detail Rows

Below shows a simple Master / Detail setup which uses setTimeout() to simulate lazying loading of data in the detail rows:

Supported Modes

The Master / Detail feature organises the grid in a way which overlaps with other features. For example, Master / Detail expands rows, which is also the case with row grouping or enterprise row model. For this reason, Master / Detail does not work with certain grid configurations. These configurations are listed below.

Row Models

The master grid (i.e. the top level grid) in Master / Detail can only be using the In Memory row model. It is not supported with Enterprise, Viewport or Infinite row models. This is because all of these row models have their own unique way of loading data which would clash with the workings on master detail.

The detail grid (i.e. the child grid) can use any of the row models. Thus as long as the master grid uses In Memory, then the detail grid can use any of the other row models.

The reason for this is that the row expand and collapse is either not support (viewport and infinite row models) or has a different meaning (enterprise row model loads more rows when you expand).

Tree Data

Master / Detail is not supported with Tree Data. This is because the concept of tree data conflicts with Master / Detail, in that in tree data, any row can expand to show child rows, which would result in a clash when a row has child rows in addition to having Master / Detail at the same row.


It is not possible to mix DOM layout for master detail. This is because the layout is a CSS setting that would be inherited by all grids contained with the master grid. So if your master grid was 'for-print', then all child grids would pick up the 'for-print' layout.

When using Master / Detail and for-print, then all detail grids need to use for-print.

When using Master / Detail and auto-height, then all detail grids need to use auto-height.