Framework:Javascript GridAngular GridReact GridVue Grid

JavaScript Grid: 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.

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:

const gridOptions = {
    columnDefs: [
        { field: "country", rowGroup: true },
        { field: "sport", rowGroup: true },

    // other grid options ...

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 year 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 year 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.

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 expand/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.

const gridOptions = {
    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 },

    // other grid options ...

To explicitly set the order of the grouping and not depend on the column order, 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.

Showing Open Groups

Setting the grid property showOpenedGroup=true will show the name of the opened group inside the group column. This is useful when the user scrolls down through the children of the group and the row showing what group was opened is scrolled out of view.

The example below uses showOpenedGroup=true with one group column. The open group is shown at the leaf level.

The following example uses showOpenedGroup=true with many group columns. The open groups are shown across all group columns where the group is open for that column.

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).

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.
  • While dragging the column header over the drop zone, before it is dropped, the column appears translucent to indicate that the grouping has not yet been applied.

Open Groups by Default

To have groups open by default, implement the grid callback isGroupOpenByDefault. This callback is invoked each time a group is created.

const gridOptions = {
    // expand when year is '2004' or when country is 'United States'
    isGroupOpenByDefault: params => {
        return (params.field == 'year' && params.key == '2004') ||
            (params.field == 'country' && params.key == 'United States');

    // other grid options ...

The params passed to the callback are as follows:

interface IsGroupOpenByDefaultParams {
  rowNode: RowNode; // the Row Node being considered
  rowGroupColumn: Column; // the Column for which this row is grouping
  level: number; // same as rowNode.level - what level the group is at, e.g. 0 for top level, 1 for second etc
  field: string; // same as rowNode.field - the field we are grouping on, e.g. 'country'
  key: any; // same as rowNode.key, the value of this group, e.g. 'Ireland'

In the example below, the country 'United States' and year '2004' are expanded by default. Note that year '2004' is expanded for all countries, not just 'United States'.

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

Configuring Full Width Group Rows

When using Full Width Group Rows, it is possible to change the rendering of the group row. This done by either replacing the Cell Renderer with your own Custom Cell Renderer, or configuring the provided Group Cell Renderer.

If using Full Width Group Rows and no groupRowRenderer properties are provided, then the default Group Cell Renderer is used with it's default values.

const gridOptions = {
    // groups by row - the grid defaults to using the default group cell renderer for the row with default settings.
    groupUseEntireRow: true,

    // other grid options ...
const gridOptions = {
    // identical to above - uses 'agGroupCellRenderer' which is the default, so doesn't change anything.
    groupUseEntireRow: true,
    groupRowRenderer: 'agGroupCellRenderer',

    // other grid options ...

Providing Cell Renderer

To provide your own Cell Renderer, use the grid properties groupRowRenderer, groupRowRendererFramework and groupRowRendererParams.

Using your own Cell Renderer hands over rendering of the full row to your custom Cell Renderer. However that also means the customer Cell Renderer will also need to provide expand / collapse functionality.

const gridOptions = {
    // configures Full Width rows with a customer Cell Renderer
    groupUseEntireRow: true,
    groupRowRenderer: 'myCellRenderer',
    groupRowRendererParams: {
        someProp: 'someValue',

    // other grid options ...

Configuring Group Cell Renderer

Configure the default Group Cell Renderer using groupRowRendererParams. Full details on what to configure are provided in the page Group Cell Renderer.

const gridOptions = {
    // use Full Width group rows and configure the Group Cell Renderer
    groupUseEntireRow: true,
    groupRowRendererParams: {
        // puts a checkbox onto each group row
        checkbox: true,
        // puts a row dragger onto each group row
        rowDrag: true

    // other grid options ...

Below shows an example of aggregating with full width rows for groups. It also provides an innerRenderer to configure what gets displaying inside the row groups, however it keeps the Default Group Cell Renderer for it's expand / collapse functionality. 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 wanta 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. ' ').

Expanding Rows via 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(node => {
    if (node.key === 'Zimbabwe') {

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'
const gridOptions = {
    columnDefs: [
      // the column definition for country uses a keyCreator
          field: "country",
          keyCreator: params =>

    // other grid options ...

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 ways for achieving the same, one using a function, one using an expression.

const gridOptions = {
    columnDefs: [
        // Option 1: use a function to return a footer value
            cellRenderer: 'agGroupCellRenderer',
            cellRendererParams: {
                footerValueGetter: params =>  {
                    return 'Total (' + params.value + ')';
        // Option 2: use an expression to return a footer value - gives same result
            cellRenderer: 'agGroupCellRenderer',
            cellRendererParams: {
                footerValueGetter: '"Total (" + x + ")"'

    // other grid options ...

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.
  • If a Footer cell is copied to the clipboard, the word "Total" will not be included. Eg where the group for "Sales" would say "Total Sales", only "Sales" will go to the clipboard. This is because the word "Total" is not actually part of the data, it's something the grid rendering puts in.

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

const gridOptions = {
    columnDefs: [
        // The column we are grouping by, it is also hidden.
        { field: "country", rowGroup: true, hide: true },

        // We choose this column as the column to show the country groups.
        { headerName: "Country - group", showRowGroup: 'country', cellRenderer: 'agGroupCellRenderer' },

    // other grid options ...

Note that the group column needs an appropriate cell renderer, in this case the out-of-the-box group cell renderer is used.

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.

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.

Grid Grouping Properties

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

Used when grouping. 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.
Default: false
If grouping, set to the number of levels to expand by default, e.g. 0 for none, 1 for first level only, etc. Set to -1 to expand everything. See Removing Single Children.
Default: 0
Allows specifying the group 'auto column' if you are not happy with the default. If grouping, this column definition is included as the first column in the grid. If not grouping, this column is not included. See Configuring the Auto Group Column.
If true, the grid will not swap in the grouping column when grouping is enabled. Use this if you want complete control over the group column displayed and do not want the grid to generate a column for you, i.e. if you already have a column in your column definitions that is responsible for displaying the groups. See Configuring the Auto Group Column.
Default: false
If using auto column, set to true to have each group in its own separate column, e.g. if grouping by Country then Year, two auto columns will be created, one for Country and one for Year. See Multi Auto Column Group.
Default: false
When true, if you select a group, the children of the group will also be selected. See Group Selection.
Default: false
If grouping, this controls 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 the 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.
Default: false
Set to true to show a 'grand total' group footer across all groups. See Grouping Footers.
Default: false
If true, and showing footer, aggregate data will always be displayed at both the header and footer levels. This stops the possibly undesirable behaviour of the header details 'jumping' to the footer on expand.
Default: false
If using groupSelectsChildren, then only the children that pass the current filter will get selected. See Group Selection.
Default: false
Shows the open group in the group column for non-group rows. See Showing Open Groups.
Default: false
Set to true to collapse groups that only have one child. See Remove Single Children.
Default: false
Set to true to collapse lowest level groups that only have one child. See Remove Single Children.
Default: false
Set to true to hide parents that are open. When used with multiple columns for showing groups, it can give a more pleasing user experience. See Group Hide Open Parents.
Default: false
When to show the 'row group panel' (where you drag rows to group) at the top. See Column Tool Panel Example.
Default: 'never'
Options: 'never', 'always', 'onlyWhenGrouping'
By default, when a column is un-grouped it is made visible. e.g. on main demo: 1) group by country by dragging (action of moving column out of grid means column is made visible=false); then 2) un-group by clicking 'x' on the country column in the column drop zone; the column is then made visible=true. This property stops the column becoming visible again when un-grouping.
Default: false

Grid Grouping Callbacks

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 is 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.
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.