DevExtreme React - Grouping

User Interaction

Group Data

A user can group data in the DataGrid using a column header's context menu or the group panel.

DevExtreme HTML5 JavaScript jQuery Knockout Angular DataGrid Grouping Group Panel Context Menu

Assigning true to the grouping.contextMenuEnabled option adds grouping commands to the context menu. Setting the groupPanel.visible option to true shows the group panel. The latter option also accepts the "auto" value that hides the group panel on small screens.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        grouping: {
            contextMenuEnabled: true
        },
        groupPanel: {
            visible: true   // or "auto"
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxo-grouping 
        [contextMenuEnabled]="true"> 
    </dxo-grouping>
    <dxo-group-panel 
        [visible]="true"> <!-- or "auto" -->
    </dxo-group-panel>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... > 
        <DxGrouping :context-menu-enabled="true"/>
        <DxGroupPanel :visible="true"/> <!-- or "auto" -->
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DxDataGrid,
    DxGrouping,
    DxGroupPanel
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxGrouping,
        DxGroupPanel
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    Grouping,
    GroupPanel
} from 'devextreme-react/data-grid';

class App extends React.Component {
    render() {
        return (
            <DataGrid ... >
                <Grouping contextMenuEnabled={true} />
                <GroupPanel visible={true} /> {/* or "auto" */}
            </DataGrid>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().DataGrid()
    // ...
    .Grouping(grouping => grouping.ContextMenuEnabled(true))
    .GroupPanel(groupPanel => groupPanel.Visible(true)) //or "auto"
)

You can prevent a user from dragging columns to the group panel, in which case it becomes an informative component only: a user can see the columns that participate in grouping, but cannot change them. Set the groupPanel.allowColumnDragging option to false to activate this behavior. You might want to group data initially in this case.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        // ...
        groupPanel: {
            visible: true,
            allowColumnDragging: false
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-group-panel 
        [visible]="true"
        [allowColumnDragging]="false"> 
    </dxo-group-panel>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... > 
        <DxGroupPanel
            :visible="true"
            :allow-column-dragging="false"
        />
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DxDataGrid,
    DxGroupPanel
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxGroupPanel
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    GroupPanel
} from 'devextreme-react/data-grid';

class App extends React.Component {
    render() {
        return (
            <DataGrid ... >
                <GroupPanel
                    visible={true}
                    allowColumnDragging={false}
                />
            </DataGrid>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().DataGrid()
    // ...
    .GroupPanel(groupPanel => groupPanel
        .Visible(true)
        .AllowColumnDragging(false)
    )
)

If a specific column should never take part in grouping, set its allowGrouping option to false. Such a column cannot be dragged to the group panel, and its context menu does not contain grouping commands.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        // ...
        columns: [{
            dataField: "id",
            allowGrouping: false
        }, 
        // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxi-column 
        dataField="id" 
        [allowGrouping]="false">
    </dxi-column>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... > 
        <DxColumn
            data-field="id"
            :allow-grouping="false"
        />
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DxDataGrid,
    DxColumn
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    Column
} from 'devextreme-react/data-grid';

class App extends React.Component {
    render() {
        return (
            <DataGrid ... >
                <Column
                    dataField="id"
                    allowGrouping={false} />
            </DataGrid>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().DataGrid()
    // ...
    .Columns(columns => {
        columns.AddFor(m => m.id)
            .AllowGrouping(false);
    })
)

Local Grouping Demo Remote Grouping Demo

Expand and Collapse Groups

A user expands or collapses a group row by clicking its expand/collapse button.

DevExtreme HTML5 JavaScript jQuery Knockout Angular DataGrid Grouping Expanded and Collapsed Rows

Set the grouping.expandMode option to "rowClick" to allow a user to expand or collapse a group row by clicking it as it could be difficult to press this button on small-screen devices.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        grouping: {
            // ...
            expandMode: "rowClick"  // or "buttonClick"
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxo-grouping ...
        expandMode="rowClick">  <!-- or "buttonClick" -->
    </dxo-grouping>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

You can prevent a user from expanding and collapsing groups by assigning false to the grouping.allowCollapsing option. After that, you can expand and collapse groups only programmatically.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        grouping: {
            // ...
            allowCollapsing: false
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxo-grouping ...
        [autoExpandAll]="true"
        [allowCollapsing]="false">
    </dxo-grouping>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

Clear Grouping

Usually, users ungroup data using the same context menu and group panel that they use for grouping. The context menu is now available not only for column headers but for group rows as well.

DevExtreme HTML5 JavaScript jQuery Knockout Angular DataGrid Grouping Row Context Menu

When ungrouping data with the group panel, users drag-and-drop column headers from it back to other column headers. If reordering is enabled, the column is placed where its header lands; if not, it gets its position from the columns array.

DevExtreme HTML5 JavaScript jQuery Knockout Angular DataGrid Grouping Row Context Menu

See Also

API

Group Index and Key

A group index is a non-negative integer that specifies a column's group order. This column's values become group keys. A nested group's key includes all parent groups' keys.

DevExtreme HTML5 JavaScript jQuery Knockout Angular DataGrid Grouping Group Index Group Key

Initial and Runtime Grouping

Assign a non-negative integer to the columns.groupIndex option to group data initially. In the following example, data is first grouped by the "Continent" field, then by the "Country" field.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        columns: [
            { dataField: 'Country', groupIndex: 1 },
            { dataField: 'Continent', groupIndex: 0 },
            // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxi-column 
        dataField="Country"
        [groupIndex]="1">
    </dxi-column>
    <dxi-column 
        dataField="Continent"
        [groupIndex]="0">
    </dxi-column>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

You can change a column's groupIndex at runtime using the columnOption(id, optionName, optionValue) method.

jQuery
JavaScript
$("#dataGridContainer").dxDataGrid("columnOption", "City", "groupIndex", 0);
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    // Prior to Angular 8
    // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    groupByCity() () {
        this.dataGrid.instance.columnOption("City", "groupIndex", 0);
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
See Also

Expand and Collapse Groups

The DataGrid provides the following API for expanding and collapsing groups:

  • All groups
    You can expand and collapse all groups at once by calling the expandAll(groupIndex) and collapseAll(groupIndex) methods without arguments. Groups appear already expanded, a behavior you can change by setting the grouping.autoExpandAll option to false.

    jQuery
    JavaScript
    $(function () {
        var dataGrid = $("#dataGridContainer").dxDataGrid({
            // ...
            grouping: { 
                autoExpandAll: false
            }
        }).dxDataGrid("instance");
        function expandAll () {
            dataGrid.expandAll();
        }
        function collapseAll () {
            dataGrid.collapseAll();
        }
    });
    Angular
    HTML
    TypeScript
    <dx-data-grid ... >
        <dxo-grouping 
            [autoExpandAll]="false">
        </dxo-grouping>
    </dx-data-grid>
    import { ..., ViewChild } from "@angular/core";
    import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
    // ...
    export class AppComponent {
        @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
        // Prior to Angular 8
        // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
        collapseAll () {
            this.dataGrid.instance.collapseAll();
        }
        expandAll () {
            this.dataGrid.instance.expandAll();
        }
    }
    @NgModule({
        imports: [
            // ...
            DxDataGridModule
        ],
        // ...
    })
  • Groups of a specific level
    The same expandAll(groupIndex) and collapseAll(groupIndex) methods expand and collapse groups of a specific level if you pass a non-negative integer as the groupIndex parameter to them. It is the same groupIndex that a column gets when it participates in grouping. The column's autoExpandGroup option specifies the initial state of groups of this level.

    jQuery
    JavaScript
    $(function () {
        var dataGrid = $("#dataGridContainer").dxDataGrid({
            // ...
            columns: [
                { dataField: 'firstName', groupIndex: 0 },
                { dataField: 'lastName', groupIndex: 1, autoExpandGroup: false },
                // ...
            ]
        }).dxDataGrid("instance");
        function expandDataGroupedByLastName () {
            dataGrid.expandAll(1);
        }
    });
    Angular
    HTML
    TypeScript
    <dx-data-grid ... >
        <dxi-column 
            dataField="firstName"
            [groupIndex]="0">
        </dxi-column>
        <dxi-column 
            dataField="lastName"
            [groupIndex]="1"
            [autoExpandGroup]="false">
        </dxi-column>
    </dx-data-grid>
    import { ..., ViewChild } from "@angular/core";
    import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
    // ...
    export class AppComponent {
        @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
        // Prior to Angular 8
        // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
        expandDataGroupedByLastName () {
            this.dataGrid.instance.expandAll(1);
        }
    }
    @NgModule({
        imports: [
            // ...
            DxDataGridModule
        ],
        // ...
    })
  • Individual groups
    The expandRow(key) and collapseRow(key) methods expand and collapse an individual group. You can check the group's current state using the isRowExpanded(key) method.

    jQuery
    JavaScript
    function toggleGroup (groupKey) {
        var dataGrid = $("#dataGridContainer").dxDataGrid("instance");
        if (dataGrid.isRowExpanded(groupKey)) {
            dataGrid.collapseRow(groupKey);
        } else {
            dataGrid.expandRow(groupKey);
        }
    }
    Angular
    TypeScript
    import { ..., ViewChild } from "@angular/core";
    import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
    // ...
    export class AppComponent {
        @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
        // Prior to Angular 8
        // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
        toggleGroup (groupKey) {
            if (this.dataGrid.instance.isRowExpanded(groupKey)) {
                this.dataGrid.instance.collapseRow(groupKey);
            } else {
                this.dataGrid.instance.expandRow(groupKey);
            }
        }
    }
    @NgModule({
        imports: [
            // ...
            DxDataGridModule
        ],
        // ...
    })
See Also

Clear Grouping

Set a column's groupIndex to undefined using the columnOption(id, optionName, optionValue) method to ungroup data by this column.

jQuery
JavaScript
$("#dataGridContainer").dxDataGrid("columnOption", "City", "groupIndex", undefined);
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    // Prior to Angular 8
    // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    clearGroupingByCity() () {
        this.dataGrid.instance.columnOption("City", "groupIndex", undefined);
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

You can ungroup data by all columns at once using the clearGrouping() method.

jQuery
JavaScript
$("#dataGridContainer").dxDataGrid("clearGrouping");
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    // Prior to Angular 8
    // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    clearGrouping() () {
        this.dataGrid.instance.clearGrouping();
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
See Also

Events

You can execute certain commands before or after a row was expanded or collapsed by handling the rowExpanding, rowExpanded, rowCollapsing or rowCollapsed event. Assign event handling functions to the corresponding onEventName options when you configure the widget if these functions are going to remain unchanged.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        onRowExpanding: function (e) {
            // Handler of the "rowExpanding" event
        },
        onRowExpanded: function (e) {
            // Handler of the "rowExpanded" event
        },
        onRowCollapsing: function (e) {
            // Handler of the "rowCollapsing" event
        },
        onRowCollapsed: function (e) {
            // Handler of the "rowCollapsed" event
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...
    (onRowExpanding)="onRowExpanding($event)"
    (onRowExpanded)="onRowExpanded($event)"
    (onRowCollapsing)="onRowCollapsing($event)"
    (onRowCollapsed)="onRowCollapsed($event)">
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    onRowExpanding (e) {
        // Handler of the "rowExpanding" event
    },
    onRowExpanded (e) {
        // Handler of the "rowExpanded" event
    },
    onRowCollapsing (e) {
        // Handler of the "rowCollapsing" event
    },
    onRowCollapsed (e) {
        // Handler of the "rowCollapsed" event
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

If you are going to change event handlers at runtime, or if you need to attach several handlers to a single event, subscribe to the events using the on(eventName, eventHandler) method. This approach is more typical of jQuery.

JavaScript
var rowCollapsedEventHandler1 = function (e) {
    // First handler of the "rowCollapsed" event
};

var rowCollapsedEventHandler2 = function (e) {
    // Second handler of the "rowCollapsed" event
};

$("#dataGridContainer").dxDataGrid("instance")
    .on("rowCollapsed", rowCollapsedEventHandler1)
    .on("rowCollapsed", rowCollapsedEventHandler2);
See Also