Row Grouping

This page shows how to group your rows. It starts off with Auto Column Groups, the simplest way to configure row groups and then builds up into more advanced topics for row grouping.

Remember Row Grouping works with all frameworks eg Angular and React as well as plain JavaScript.

Specifying Group Columns

To group rows by a particular column, mark the column you want to group with rowGroup=true. There is no limit on the number of columns that the grid can group by. For example, the following will group the rows in the grid by country and then sport: gridOptions.columnDefs = [ {headerName: "Country", field: "country", rowGroup: true}, {headerName: "Sport", field: "sport", rowGroup: true}, ];

To allow a column to be grouped when using the Tool Panel set enableRowGroup=true on the required columns. Otherwise you won't be able to drag and drop the columns to the grouping drop zone from the Tool Panel.

Auto Column Group

As you can see in the example below, as soon as there is at least one active row group, the grid will provide an additional column for displaying the groups in a tree structure with expand/collapse navigation.

  • There is a group column at the left that lets you open/close the groups. It also shows the amount of rows grouped in brackets.
  • Sorting works out of the box in the group column. You can test this by clicking on the group column header.
  • The country and sport columns used for grouping are still shown as normal. You can hide them by adding hide: true to their colDef as illustrated in the Multi Auto Column example.

Multi Auto Column Group

The grid also lets you automatically create one column for each individual group. This is achieved by setting gridOptions.groupMultiAutoColumn = true. The following example illustrates this. Note that:

  • There is a group column displayed for each column that we are grouping by (in this case the country and year columns).
  • Sorting works out of the box in each of these group column. You can test this by clicking on the group column header.
  • The country and sport columns used for grouping are hidden so that we don't show redundant information. This is done by setting colDef.hide = true.

Configuring the Auto Group Column

You can specify your own configuration used by the auto group columns by providing a gridOptions.autoGroupColumnDef. This can be used to override any property as defined in the Columns documentation page

The auto columns generated by the grid use the ag-Grid provided group cell renderer. This means that gridOptions.autoGroupColumnDef can also be used to pass additional properties to further customise how your groups are displayed.

Check the cell rendering docs to see all the available parameters available to configure the group cell renderer.

The following example illustrates how you can configure the auto group columns. Note that:

  • For the purpose of simplification this example uses one Auto Row Group Column. If you were to use Multi Auto Group Column the configuration would be applied to all the generated columns
  • The header name of the group column is changed by setting in autoGroupColumnDef.headerName = 'CUSTOM!'
  • The count for each group is removed by setting autoGroupColumnDef.cellRendererParams.suppressCount = true
  • Each group has a select box by setting autoGroupColumnDef.cellRendererParams.checkbox = true
  • The group column has a custom comparator that changes the way sorting works, this is achieved by setting autoGroupColumnDef.comparator = function (left, right){...}. The custom comparator provided in the example changes the way the sorting works by ignoring the first letter of the group. To test this click on the header. When sorting desc you should see countries which second letter goes from Z..A, asc should show countries which second letter goes A..Z

Filtering on Group Columns

Filter on group columns is more complex than filtering on normal columns as the data inside the column can be a mix of data from different columns. For example if grouping by Country and Year, should the filter be for Year or for Country?

For auto generated group columns, the filter will work if you specify one of field, valueGetter or filterValueGetter.

Adding Values To Leaf Nodes

You may have noticed in the examples so far that the group columns don't produce values on the leaf nodes, the cells are empty. If you want to add values you can add a valueGetter or field to the colDef and it will be used to render the leaf node.

A side effect of this is that filtering will now work for the columns using the field values.

This example shows specifying field in the auto group column. Note the following:

  • The group column shows both groups (Country and Year) as well as Athlete at the leaf level.
  • The field (Athlete) is used for filtering.

Adding leaf nodes data can also be achieved even if you provide your own group columns, this is illustrated in the following example. Note the following:

  • The first column shows the Country group only. The filterValueGetter is configured to return the country so that country is used for filtering.
  • The second columns shows Year (for group levels) and Athlete (for leaf levels). Because the field is set, the filter will use the field value for filtering.
  • This is an example of a case where not using auto group columns lets us add custom different behaviour to each of the grouping columns.

Group Cell Rendering

If you use the default group cell renderer provided by ag-grid, there are many parameters that can be passed to configure its behaviour, they are all explained in the Group Cell Renderer documentation. Please have a look at this docs if you are interested in finding our how to change the contents that are displayed in each grouped cell.

You can also configure the look & feel of the expan/contract buttons by specifying your own custom icons.

Specifying Row Group Order

By default, if you are using a column to display more than one group, the grid will order the groups based in the order in which you provide the columns. The following code snipped will group by country first, then sport second. columnDefs = [ // country listed first, gets grouped first {headerName: "Country", field: "country", rowGroup: true}, // sport listed second, gets grouped second {headerName: "Sport", field: "sport", rowGroup: true}, ];

To explicitly set the order of the grouping and not depend on the column order, then use rowGroupIndex instead of rowGroup as follows:

columnDefs = [ // index = 1, gets grouped second {headerName: "Country", field: "country", rowGroupIndex: 1}, // index = 0, gets grouped first {headerName: "Sport", field: "sport", rowGroupIndex: 0}, ];

The grid will order sort the columns based on the rowGroupIndex. The values can be any numbers that are sortable, they do NOT need to start at zero (or one) and the sequence can have gaps.

Using rowGroup=true is simpler and what most people will prefer using. You will notice that rowGroupIndex is used by the column API getColumnState() method as this cannot depend on the order of the column definitions.

The following examples shows using rowGroupIndex to set the order of the group columns. Year is grouped first and Country is grouped second.

Hide Open Parents

Depending on your preference, you may wish to hide parent rows when they are open. This gives the impression to the user that the children takes the place of the parent row. This feature only makes sense when groups are in different columns. To turn this feature on set groupHideOpenParents=true.

Below shows examples of this. Notice that each group row has aggregated values which are explained in a documentation page of their own. When the group is closed, the group row shows the aggregated result. When the group is open, the group row is removed and in its place the child rows are displayed. To allow closing the group again, the group column knows to display the parent group in the group column only (so you can click on the icon to close the group).

Example Hide Open Parents

The example below demonstrates hiding open parents using auto group columns. To help demonstrate, the grid is configured to shade the rows different colors for the different group levels, so when you open a group, you can see the background change indicating that the group row is no longer display, instead the children are in it's place.

Filter is achieved for each column by providing a filterValueGetter for the autoGroupColumnDef. The filterValueGetter returns the value of the grouped column - eg for Country, it will filter on Country.

Keeping Columns Visible

By default dragging a column out of the grid will make it hidden and un-grouping a column will make it visible again. This default behaviour can be changed with the following properties:

  • suppressDragLeaveHidesColumns: When dragging a column out of the grid, eg when dragging a column from the grid to the group drop zone, the column will remain visible.
  • suppressMakeColumnVisibleAfterUnGroup: When un-grouping, eg when clicking the 'x' on a column in the drop zone, the column will not be made visible.
The default behaviour is more natural for most scenarios as it stops data appearing twice. E.g. if country is displayed in group column, there is no need to display country again in the country column.

The example below demonstrates these two properties. Note the following:

  • Columns country and year can be grouped by dragging the column to the group drop zone.
  • Grouped columns can be un-grouped by clicking the 'x' on the column in the drop zone.
  • The column visibility is not changed while the columns are grouped and un-grouped.

Full Width Group Rows

Instead of having a column for showing the groups, you can dedicate the full row for showing details about the group. This can be preferred if you have a lot of information you want to say about the group.

The following example shows the first example in this page, the Auto Column Group example, using full width rows. Note that all that is necessary to achieve this it to add groupUseEntireRow:true to your gridOptions

Full Width Groups Rendering

It is possible to override the rendering of the group row using groupRowRenderer and groupRowInnerRenderer. Use groupRowRenderer to take full control of the row rendering, and provide a cellRenderer exactly how you would provide one for custom rendering of cells for non-groups.

The following pieces of code do the exact same thing: // option 1 - tell the grid to group by row, the grid defaults to using // the default group cell renderer for the row with default settings. gridOptions.groupUseEntireRow = true; // option 2 - this does the exact same as the above, except we configure // it explicitly rather than letting the grid choose the defaults. // we tell the grid what renderer to use (the built in renderer) and we // configure the default renderer with our own inner renderer gridOptions.groupUseEntireRow = true; gridOptions.groupRowRenderer: 'agGroupCellRenderer'; gridOptions.groupRowRendererParams: { innerRenderer: function(params) {return params.node.key;}, }; // option 3 - again the exact same. we allow the grid to choose the group // cell renderer, but we provide our own inner renderer. gridOptions.groupUseEntireRow = true; gridOptions.groupRowInnerRenderer: function(params) {return params.node.key;};

The above probably reads a bit confusing. So here are rules to help you choose:

  • If you are happy with what you get with just setting groupUseEntireRow = true, then stick with that, don't bother with the renderers.
  • If you want to change the inside of the renderer, but are happy with the expand / collapse etc of the group row, then just set the groupRowInnerRenderer.
  • If you want to customise the entire row, you are not happy with what you get for free with the group cell renderer, then set your own renderer with groupRowRenderer, or use groupRowRenderer to configure the default group renderer.

Here is an example of taking full control, creating your own renderer. In practice, this example is a bit useless, as you will need to add functionality to at least expand and collapse the group, however it demonstrates the configuration:

gridOptions.groupUseEntireRow = true; gridOptions.groupRowRenderer: function(params) {return params.node.key;};

This example takes full control also, but uses the provided group renderer but configured differently by asking for a checkbox for selection:

gridOptions.groupUseEntireRow = true; gridOptions.groupRowRenderer: 'agGroupCellRenderer'; gridOptions.groupRowRendererParams: { checkbox: true, // innerRenderer is optional, we could leave this out and use the default innerRenderer: function(params) {return params.node.key;}, }

Below shows an example of aggregating with full width rows for groups. The following can be noted:

  • Each group spans the width of the grid.
  • Each group uses a custom Cell Renderer. The cell renderer shows the aggregation data for each medal type.
  • Each medal column is editable, you can change the number of medals for any of the athletes.
  • The column Year has a filter on it.
  • The cell renderer has logic listening for changes to filtering and data cell changes*. This means the aggregation data in the full with row is updated if:
    1. If you edit any cell
    2. If you filter the data (ie take rows out).

* This is true for Vanilla Javascript and React. Angular uses data binding and thus the aggregation data updates automatically without needing to listen to events.

Default Group Order

The grid does not attempt to order the groups. The groups are presented on a 'first come, first served' basis. For example if grouping by country, and the first row is for country 'Ireland', then the first displayed group will be 'Ireland'.

For most scenarios, this will not be a problem as the user can sort the grouping column. However this will be a problem in one of the following cases:

  • The grid is using Full Width Group Rows, which means there is no columns associated with the groups to order.
  • The groups have an implied order that should not require column sorting to achieve. For example grouping by month (January, February...) or other groups which have business meaning that require order e.g. ["Severe", "Medium", "Low"] or ["Today", "Yesterday", "Older than 1 day"].

To provide a group order, you should supply defaultGroupSortComparator callback to the grid. The callback is a standard JavaScript Array comparator that takes two values and compares them.

The example below shows providing a default group order. From the example the following can be noted:

  • Groups are displayed using full width rows. There is no column to click to sort the groups.
  • The grid is provided with defaultGroupSortComparator.
  • Groups are sorted alphabetically.

Unbalanced Groups

If there are rows containing null or undefined values for the column that is being grouped then these rows will not be grouped. We refer to this scenario as Unbalanced Groups in that there is a mix of groups and rows as siblings. The following example demonstrates:

  • Data is grouped by column 'State'. Rows are either grouped by state 'New York', 'California' or not grouped.
  • Removing the grouping shows that the non grouped rows have no 'State' value.

If you do not want rows with null or undefined to be left out of groups, but want a group created to contain these empty values, then change your data and replace the null and undefined values with something (eg the string 'Empty' or a string with a blank space character i.e. ' ').

Grouping API

To expand or contract a group via the API, you first must get a reference to the rowNode and then call rowNode.setExpanded(boolean). This will result in the grid getting updated and displaying the correct rows. For example, to expand a group with the name 'Zimbabwe' would be done as follows: gridOptions.api.forEachNode(function(node) { if (node.key==='Zimbabwe') { node.setExpanded(true); } });

Calling node.setExpanded() causes the grid to get redrawn. If you have many nodes you want to expand, then it is best to set node.expanded=true directly, and then call api.onGroupExpandedOrCollapsed() when finished to get the grid to redraw the grid again just once.

Grouping Complex Objects with Keys

If your rowData has complex objects that you want to group by, then the default grouping will convert each object to "[object object]" which will be useless to you. Instead you need to get the grid to convert each object into a meaningful string to act as the key for the group. You could add a 'toString' method to the objects - but this may not be possible if you are working with JSON data. To get around this, use colDef.keyCreator, which gets passed a value and should return the string key for that value.

The example below shows grouping on the county, with country an object within each row.

// row item has complex object for country rowItem = { athlete: 'Michael Phelps', country: { name: 'United States', code: 'US' } .... } // the column definition for country has keyCreator colDef = { headerName: "Country", field: "country", keyCreator: function(params) { return params.value.name; } ... }

Grouping Footers

If you want to include a footer with each group, set the property groupIncludeFooter to true. The footer is displayed as the last line of the group when the group is expanded - it is not displayed when the group is collapsed.

The footer by default will display the word 'Total' followed by the group key. If this is not what you want, then use the footerValueGetter option. The following shows two snippets for achieving the same, one using a function, one using an expression.

// use a function to return a footer value cellRenderer:'agGroupCellRenderer', cellRendererParams: { footerValueGetter: function(params) { return 'Total (' + params.value + ')'}, }} // use an expression to return a footer value. this gives the same result as above cellRenderer:'agGroupCellRenderer', cellRendererParams: { footerValueGetter: '"Total (" + x + ")"' }}

When showing the groups in one column, the aggregation data is displayed in the group header when collapsed and only in the footer when expanded (ie it moves from the header to the footer). To have different rendering, provide a custom groupInnerCellRenderer, where the renderer can check if it's a header or footer.

It is also possible to include a 'grand' total footer for all groups using the property groupIncludeTotalFooter. This property can be used along side groupIncludeFooter to produce totals at all group levels or used independently.

The example below uses aggregation which is explained in the next section but included here as footer rows only make sense when used with aggregation. In this example notice:

  • gridOptions.groupIncludeFooter = true - includes group totals within each group level.
  • gridOptions.groupIncludeTotalFooter = true - includes a 'grand' total across all groups.
Group footers are a UI concept only in the grid. It is the grids way of showing aggregated data (which belongs to the group) appearing after the group's children. Because the footer is a UI concept only, the following should be noted:
  • It is not possible to select footer nodes. Footer rows appear selected when the group is selected.
  • Footer rows are not parted of the iterated set when the api method api.forEachNode() is called.
  • Footer nodes are not exported to CSV or Excel.

Keeping Group State

If using transactions or delta updates, then you do not need to be concerned with keeping group state. When using transactions or delta updates, the group state is not changed.

When you set new data into the group by default all the group open/closed states are reset. If you want to keep the original state, then set the property rememberGroupStateWhenNewData=true. The example below demonstrates this. Only half the data is shown in the grid at any given time, either the odd rows or the even rows. Hitting the 'Refresh Data' will set the data to 'the other half'. Note that not all groups are present in both sets (eg 'Afghanistan' is only present in one group) and as such the state is not maintained. A group like 'Australia' is in both sets and is maintained.

Removing Single Children

If your data has groups with only one child, then it can make sense to collapse these groups as there is no benefit to the user creating groups with just one child, it's arguably waste of space.

To turn this feature on set either groupRemoveSingleChildren=true or groupRemoveLowestSingleChildren=true.

  • groupRemoveSingleChildren: Removes groups from display if they only have one child.
  • groupRemoveLowestSingleChildren: Removes groups from display if they only have one child and the groups is at the lowest level (ie contains leaf nodes).

The example below shows this feature. Note the following:

  • Normal: Shows the rows as normal, nothing is removed. All groups have their children count in brackets after the group.
  • Remove Single Children: Removes single children using the property groupRemoveSingleChildren=true. All groups with just one child are remove.
  • Remove Lowest Single Children: Removes single children using the property groupRemoveLowestSingleChildren=true. All groups for the 'City' column with just one child are remove. The 'City' column is the lowest level group, so it's the only group candidate to be removed when one child.

Filtering does not impact what groups get removed. For example if you have a group with two children, the group is not removed, even if you apply a filter that removes one of the children. This is because ag-Grid does grouping first and then applies filters second. If you change the filter, only the filter is reapplied, the grouping is not reapplied. The properties groupRemoveSingleChildren, groupRemoveLowestSingleChildren and groupHideOpenParents are mutually exclusive, you can only pick one. Technically it doesn't make sense to mix these. They don't work together as the logic for removing single children clashes with the logic for hiding open parents. Both want to remove parents at different times and for different reasons.

Creating Your Own Group Display Columns

In all the previous examples the grid is in charge of generating the column's that display the groups, these columns are called auto group columns.

You can prevent the generation of the auto group columns and take control over which columns display which groups. This is useful if you want to have a finer control over how your groups are displayed.

We advise against using your own group columns. Only do this if the Auto Group Columns do not meet your requirements. Otherwise defining your own group columns will add unnecessary complexity to your code.

To disable the auto group columns set gridOptions.groupSuppressAutoColumn = true. When you do this, you will be in charge of configuring which columns show which groups.

In order to make a column display a group, you need to configure the property coldef.showRowGroup for that column.

coldef.showRowGroup can be configured in two different fashions.

  • To tell this column to show all the groups: coldef.showRowGroup= true
  • To tell this column to show the grouping for a particular column. If you want to do this you need to know the colId of the column that you want to show the group by and set coldef.showRowGroup= colId

If you do specify coldef.showRowGroup you are going to also tell this column how to display the contents of this group, the easiest way to do this is by using the out of the box group cell renderer cellRenderer:'agGroupCellRenderer'

This illustrates how to configure an specific column to show the groups generated by the country column

coldefs:[ // The column we are grouping by, it is also hidden. {headerName: "Country", field: "country", width: 120, rowGroup:true, hide:true}, // We appoint this column as the column to show the country groups. // note that we need to provide an appropriate cell renderer. // in this case we are using the out of the box group cell renderer. {headerName: "Country - group", showRowGroup: 'country', width: 120, cellRenderer:'agGroupCellRenderer'}, ]

The following example shows how to appoint individual columns to show individual groups

The following example shows how to display all the groups in a single column

The last example of explicitly setting groups shows an alternative for Hide Open Parents. The example below demonstrates hiding open parents using explicit group columns.

Remember these examples are achieving the same that you can achieve with the auto groups columns, but their configuration is not as straight forward. We are keeping this for edge cases and for backwards compatibility for when we only supported this style of configuration.

Grid Grouping Properties

Grouping has the following grid properties (set these as grid properties, e.g. on the gridOptions, not on the columns):

Property Description
groupUseEntireRow If grouping, set to true or false (default is false). If true, a group row will span all columns across the entire width of the table. If false, the cells will be rendered as normal and you will have the opportunity to include a grouping column (normally the first on the left) to show the group. See Full Width Group Rows.
groupDefaultExpanded If grouping, set to the number of levels to expand by default. Eg 0 for none, 1 first level only, etc. Default is 0 (expand none). Set to -1 for expand everything. See example Removing Single Children.
autoGroupColumnDef Allows specifying the group 'auto column' if you are not happy with the default. If grouping, this column def is included as the first column definition in the grid. If not grouping, this column is not included. See Configuring the Auto Group Column.
groupSuppressAutoColumn If true, the grid will not swap in the grouping column when grouping is enabled. Use this if you want complete control on the column displayed and don't want the grids help. In other words, you already have a column in your column definitions that is responsible for displaying the groups. See Configuring the Auto Group Column.
groupMultiAutoColumn If using auto column, set to true to have each group in its own column separate column, eg if group by Country then Year, two auto columns will be created, one for country and one for year. See Multi Auto Column Group.
groupSuppressRow If true, the group row won't be displayed and the groups will be expanded by default with no ability to expand / contract the groups. Useful when you want to just 'group' the rows, but not add parent group row to each group. See Suppress Group Row.
groupSelectsChildren When true, if you select a group, the the children of the group will also get selected. See Group Selection.
groupIncludeFooter If grouping, whether to show a group footer when the group is expanded. If true, then by default, the footer will contain aggregate data (if any) when shown and the header will be blank. When closed, the header will contain the aggregate data regardless of this setting (as footer is hidden anyway). This is handy for 'total' rows, that are displayed below the data when the group is open, and alongside the group when it is closed See Grouping Footers.
groupIncludeTotalFooter Set to true to show a 'grand' total group footer across all groups. See Grouping Footers.
groupSuppressBlankHeader If true, and showing footer, aggregate data will be displayed at both the header and footer levels always. This stops the possibly undesirable behaviour of the header details 'jumping' to the footer on expand.
groupSelectsFiltered If using groupSelectsChildren, then only the children that pass the current filter will get selected. See Group Selection.
groupRemoveSingleChildren Set to true to collapse groups that only have one child. See Remove Single Children.
groupRemoveLowestSingleChildren Set to true to collapse lowest level groups that only have one child. See Remove Single Children.
groupHideOpenParents Set to true to hide parents that are open. When used with multiple columns for showing groups, it can give more pleasing user experience. See Group Hide Open Parents.
rowGroupPanelShow When to show the 'row group panel' (where you drag rows to group) at the top. Default is never. Set to either 'always' or 'onlyWhenGrouping'. See Tool Panel Example.

Grid Grouping Callbacks

Callback Description
groupRowRenderer, groupRowRendererParams If grouping, allows custom rendering of the group cell. Use this if you are not happy with the default presentation of the group. This is only used when groupUseEntireRow=true. This gives you full control of the row, so the grid will not provide any default expand / collapse or selection checkbox. See section on cellRendering for details on params.
groupRowInnerRenderer Similar to groupRowRenderer, except the grid will provide a default shell for row which includes an expand / collapse function. The innerRenderer is responsible for just the inside part of the row. There is no groupRowInnerRendererParams as the groupRowRendererParams are reused for both.