Expand All

  Getting Started



  Row Models




  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

Grouping Rows

To group, mark the column definitions you want to group by with a rowGroupIndex. There is no limit on the number of columns that can be used. For example, the following groups by country column, then language column:

gridOptions.columnDefs = [
    {field: 'country', rowGroupIndex: 0},
    {field: 'language', rowGroupIndex: 1}

Grouping Auto Column

If row grouping is active, by default the grid will provide an additional column for displaying a tree structure, with expand / collapse navigation, for displaying the groups.

The auto column only displaying when row grouping is active is useful when the user is turning grouping on and off via the toolpanel.

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.
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.
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 black. 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.
groupColumnDef 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.
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.
groupMultiAutoColumn If using auto column, set to true to have each group in it's own column separate column, eg if group by Country then Year, two auto columns will be created, one for country and one for year.
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.
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.
groupSelectsChildren When true, if you select a group, the the children of the group will also get selected.
groupSelectsFiltered If using groupSelectsChildren, then only the children that pass the current filter will get selected.
groupRemoveSingleChildren Set to true to collapse groups that only have one child.
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.
animateRows Set to true to enable animation of the rows after group is opened and closed.
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

Simple Example

To get the discussion going, below is presented a simple grouping example where all the data is grouped by country. You will also notice:

  • The group parent row has no cells, it spans the full width of the grid.
  • Animation is turned for when groups open and close.
  • The 'Toggle Zimbabwe' button at the top uses the grid's API to open and close the group.

Grouping Columns vs Full Width Groups

You can represent group rows in your grid in two ways:

  1. Grouping Column: One column (usually the left most column) will display the group information with the expand / contract icons. The row then display the rest of the cells as normal (eg if a sum aggregate was used, it could be displayed in the other cells). This is what is used in the main ag-Grid demo.
  2. Full Width Groups: The group row does not use the cells, instead on cell for the group spans the entire width of the grid. This is used in the first example above.

Grouping Columns

If you decide to group using the entire row (groupUseEntireRow = true), then you don't need to use grouping columns, and this section is not relevant.

If you are using grouping columns, then you need to decide how to display your group column. Below shows the different options (all assume gridOptions.groupUseEntireRow = false). A group cell renderer is explained in the next section (but used here).

Option 1 - Simplest but not customisable:

Let the grid provide the default grouping column. This is the quickest way to get started.

gridOptions.groupSuppressAutoColumn = false; // or undefined
gridOptions.groupColumnDef = null; // or undefined
All you have to do is provide your columns as normal and let the grid worry about introducing the column to show the group when you are grouping.

Option 2 - Most Common:

Tell the grid how you want the optional group column to look. Do this by providing a groupColumnDef.

A group column definition is exactly the same as any other column definition, the only difference is the cell renderer will render the cell using the group info. So when defining a group column, be sure to either choose the built in group cell renderer, or provide your own cell renderer that takes care of the grouping.

gridOptions.groupSuppressAutoColumn = false; // or undefined
gridOptions.groupColumnDef = {
    cellRenderer: 'group',
    headerName: 'Group Column'

Because a group column is just a normal column, you can provide all the column attributes, such as header name, css style and class, field, valueGetter etc. All of these parameters are used as appropriate. The example above uses the provided 'group' cellRenderer - you can also use this, or you can build your own cellRenderer from scratch.

Option 3 - No Grid Swapping of Columns:

Tell the grid you don't want it's help, that you will provide the group column yourself, included in the main list of columns. If you use this, make sure you do have at least one column showing the group, otherwise the grid will not make sense as you will have no way to expand / contract the groups.

This method can also be used to have multiple columns to display the groups, useful when you want to split the grouping across columns (eg one column is responsible for the country grouping, another for the language grouping).

gridOptions.groupSuppressAutoColumn = true;
gridOptions.groupColumnDef = null; // doesn't matter, won't get used anyway

Group Cell Renderer

If grouping, you will need to dedicate a column to displaying the group, as described above. To have the column behave appropriate, you need to provide it with an appropriate cell renderer. You can either a) use the built in provided group cell renderer or b) bake your own grouping cell renderer. The provided cell renderer is selected by providing the string 'group' for the cellRenderer. You also provide params with options as follows:

colDef.cellRenderer = 'group';
colDef.cellRendererParams = {
        keyMap: {from: 'to'},
        suppressCount: false,
        checkbox: true,
        padding: 10,
        innerRenderer: myInnerRenderer,
        footerValueGetter: myFooterValueGetter

The parameters are:

  • keyMap: Map of key value pairs to display alternatives instead of the group keys. For example, if the group was 'LDN', you could display it as 'London'.
  • suppressCount: One of [true, false], if true, count is not displayed beside the name.
  • checkbox: One of [true,false], if true, a selection checkbox is included.
  • padding: A positive number. The amount of padding, in pixels, to indent each group.
  • suppressPadding: Set to true to node including any padding (indentation) in the child rows.
  • innerRenderer: The renderer to use for inside the cell (after grouping functions are added).
  • footerValueGetter: The value getter for the footer text. Can be a function or expression.
  • restrictToOneGroup: If true, the column will only show one level of group, eg 'Country', and then another column will show 'Language'.

One Or Many Group Columns

Depending on your preference, when showing multiple levels of groups, you can have one column showing all grouping levels, or one column per grouping level. To have a group column only show one level of groups, set restrictToOneGroup=true.

Below are two similar examples. The first shows the groups in one column. The second has a dedicated column for each group.

Example - Explicitly Configure One Group Column

Example - Explicitly Configure Many Group Columns

Example - Auto Configure Many Group Columns

Replacing Groups with Children When Open

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.

// OPTION 1 - configure with your own columns
var gridOptions = {
    // providing our own group cols, we don't want auto
    groupSuppressAutoColumn: true,
    groupHideOpenParents: true,
    ... // other properties here

var colDefs = {
    // the first group column
    {headerName: "Country", cellRenderer: 'group', field: "country", rowGroupIndex: 0,
        cellRendererParams: { restrictToOneGroup: true }

    // the second group column
    {headerName: "Year", cellRenderer: 'group', field: "year", rowGroupIndex: 1,
        cellRendererParams: {
            restrictToOneGroup: true
    ... // other cols here

// OR OPTION 2 - use auto columns
var gridOptions = {
    // leave this property out, as want auto columns
    // groupSuppressAutoColumn: true,

    groupHideOpenParents: true,
    ... // other properties here

var colDefs = {
    // then provide the cols we want to group by, but hide them an no specific renderer
    {field: "country", rowGroupIndex: 0, hide: true},
    {field: "year", rowGroupIndex: 1, hide: true},
    ... // other cols here

Below shows an example of this. Notice that each group row has aggregated values. When the group is closed, the group row shows the aggregated result. When the group is open, the group row is removed and in it's 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).

To help demonstrate this, the grid is configured to shade the rows different colors for the different group levels.

Grouping API

To expand or contract a group via the API, you fist 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') {

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.

rowItem = {
    athlete: 'Michael Phelps',
        country: { // country is complex object, so need to provide colDef.keyCreator()
        name: 'United States',
        code: 'US'

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 then 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: 'group',
cellRendererParams: {
    footerValueGetter: function(params) { return 'Total (' + params.value + ')'},

// use an expression to return a footer value. this gives the same result as above
cellRenderer: 'group',
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.

Note: 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.

Keeping Group State

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.

Full Width Groups

Full width groups extend the width of the grid. You have two choices when using full width groups using the property embedFullWidthRows as follows:

  • embedFullWidthRows = false: The group row will always span the width of the grid including pinned areas and is not impacted by horizontal scrolling. This is the most common usage and thus the default. The only drawback is that for some browsers (IE in particular), as you scroll vertically, the group row will lag behind the other rows.
  • embedFullWidthRows = true: The group row will be split into three sections for center, pinned left and pinned right. This is not ideal but works much faster with no IE issues.
So you might ask which one to use? The answer is the first one (just leave the property out, it's defaulted to false) unless you want to avoid IE performance issues.

Example embedFullWidthRows

The example below demonstrates embedFullWidthRows on and off as follows:

  • Both grids have columns pinned left and right.
  • Both grids have group rows spanning the grid width.
  • The top grid as embedFullWidthRows=false, the bottom grid has embedFullWidthRows=true.
So with this setup, you will notice the following difference:
  • In the top grid, the group rows are not impacted by the pinning. In the bottom grid, the groups are truncated if you make the Athlete & Year columns to small, as the groups are sitting in the pinned section.
  • In the bottom grid, if you unpin the columns (via the column menu) then the group jumps to the center.

If you are using custom group row rendering (explained below) and embedFullWidthRows = true, the panel you are rendering in is provided via the pinned parameter.

Group Row 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:  'group';
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: 'group';
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, then using the entire row to give a summary.

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 the property groupRemoveSingleChildren=true.

The example below shows this feature in action. To demonstrate why this feature is needed you can click 'Toggle Grid' to show what the grid would be like without this setting. You will see the group UK, German and Sweden have only one child so the group is not giving any extra value to the data.

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. It is not possible to mix groupRemoveSingleChildren and groupHideOpenParents. Technically, it doesn't make sense. Mixing these two will put you down a black hole so deep not even Stephen Hawking will be able to save you.

Suppress Group Row

By suppressing the group row you don't give users the ability to close the groups by themselves, but the rows are grouped and the other functionalities take the grouping into account. Sorting, for example, will sort by group.

Custom Expand / Contract Icons

See the section on icons for customising the expand / contract icons.