---
title: "Row Grouping - Sorting"
enterprise: true
framework: vue
version: "36.1.0"
---

# Row Grouping - Sorting

This section provides details on how to configure and customise how row groups are sorted.

## Sorting Row Groups

Row Groups are [Sorted](https://www.ag-grid.com/vue-data-grid/row-sorting/) by the column that they are grouped by, and use any [Custom Sorting](https://www.ag-grid.com/vue-data-grid/row-sorting/#custom-sorting) configured on that column. Applying a sort to a group column generated by `groupDisplayType` will apply the sort to the row grouped columns it represents.

#### Mixed Group Sort

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :autoGroupColumnDef="autoGroupColumnDef"
      :groupDefaultExpanded="groupDefaultExpanded"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", rowGroup: true, sort: "desc" },
      { field: "year", rowGroup: true, sort: "asc" },
      { field: "athlete" },
      { field: "total" },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      minWidth: 100,
    });
    const autoGroupColumnDef = ref<AutoGroupColumnDef>({
      minWidth: 300,
    });
    const groupDefaultExpanded = ref(1);
    const rowData = ref<any[]>(null);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      const updateData = (data) => (rowData.value = data);

      fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((data) => updateData(data));
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      autoGroupColumnDef,
      groupDefaultExpanded,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Mixed Group Sort](https://www.ag-grid.com/examples/grouping-sorting/mixed-group-sort/vue3)

The example above demonstrates that sorting the `country` and `year` columns will sort the row groups, and clicking to sort the `Group` column applies sorting to the `country` and `year` columns.

> **Note**
>
> When using `groupDisplayType` with a [Single Group Column](https://www.ag-grid.com/vue-data-grid/grouping-single-group-column/) and the columns with row grouping applied have different sort directions, the group column will instead display the mixed sort icon.

```ts
<ag-grid-vue
    :columnDefs="columnDefs"
    :groupDisplayType="groupDisplayType"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    { field: 'country', rowGroup: true, sort: 'desc' },
    { field: 'year', rowGroup: true, sort: 'asc' },
    // ...other column definitions
];
this.groupDisplayType = 'singleColumn';
```

## Custom Row Group Sorting

The generated Group Columns can be unlinked from the columns with row grouping by configuring [Custom Group Sorting](https://www.ag-grid.com/vue-data-grid/row-sorting/#custom-sorting) using a `autoGroupColumnDef.comparator`. This allows custom sorting to be applied across all levels of row grouping.

The example below demonstrates a configuration that ignores the data entirely, sorting rows by the number of descendants instead:

```ts
<ag-grid-vue
    :columnDefs="columnDefs"
    :autoGroupColumnDef="autoGroupColumnDef"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    { field: 'country', rowGroup: true },
    { field: 'year', rowGroup: true },
    // ...other column definitions
];
this.autoGroupColumnDef = {
    comparator: (valueA, valueB, nodeA, nodeB) => {
        return nodeA.allLeafChildren.length - nodeB.allLeafChildren.length;
    },
};
```

#### Custom Group Sort

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :autoGroupColumnDef="autoGroupColumnDef"
      :groupDefaultExpanded="groupDefaultExpanded"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", rowGroup: true },
      { field: "year", rowGroup: true },
      { field: "athlete" },
      { field: "total" },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      minWidth: 100,
    });
    const autoGroupColumnDef = ref<AutoGroupColumnDef>({
      minWidth: 300,
      comparator: (valueA, valueB, nodeA, nodeB) =>
        (nodeA.allLeafChildren?.length ?? 0) -
        (nodeB.allLeafChildren?.length ?? 0),
    });
    const groupDefaultExpanded = ref(1);
    const rowData = ref<any[]>(null);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      const updateData = (data) => (rowData.value = data);

      fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((data) => updateData(data));
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      autoGroupColumnDef,
      groupDefaultExpanded,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Custom Group Sort](https://www.ag-grid.com/examples/grouping-sorting/custom-group-sort/vue3)

> **Note**
>
> When using custom group sorting, sorting the `Group` column no longer impacts the columns with row grouping, and vice versa.

## Maintain Group Order

By default, sorting on a non-group column reorders groups based on the sort. To keep groups in their structural order while only sorting the rows within each group, enable `groupMaintainOrder`:

```ts
<ag-grid-vue
    :columnDefs="columnDefs"
    :groupMaintainOrder="groupMaintainOrder"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    { field: 'country', rowGroup: true, hide: true },
    { field: 'athlete' },
];
this.groupMaintainOrder = true;
```

With `groupMaintainOrder=true`:

- Sorting a leaf column sorts the rows inside each group; groups stay in structural order.
- Filter changes preserve group order.
- Transactions add new groups at their structural position: the end of the data-insertion order, or the position produced by `initialGroupOrderComparator` if one is configured.
- With multi-level row grouping, the order is maintained per level. Sorting a group column at one level only re-orders that level's groups; sibling levels keep their structural order. For example, with `country` and `year` grouping, sorting `year` re-orders year groups within each country, while country groups remain in their structural slot.

#### Maintain Group Order

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  RowGroupingDisplayType,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :autoGroupColumnDef="autoGroupColumnDef"
      :groupDisplayType="groupDisplayType"
      :groupMaintainOrder="true"
      :groupDefaultExpanded="groupDefaultExpanded"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", rowGroup: true, hide: true },
      { field: "year", rowGroup: true, hide: true },
      { field: "athlete" },
      { field: "total" },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      minWidth: 100,
    });
    const autoGroupColumnDef = ref<AutoGroupColumnDef>({
      minWidth: 200,
    });
    const groupDisplayType = ref<RowGroupingDisplayType>("multipleColumns");
    const groupDefaultExpanded = ref(1);
    const rowData = ref<any[]>(null);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      const updateData = (data) => (rowData.value = data);

      fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((data) => updateData(data));
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      autoGroupColumnDef,
      groupDisplayType,
      groupDefaultExpanded,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Maintain Group Order](https://www.ag-grid.com/examples/grouping-sorting/maintain-group-order/vue3)

The example above uses `groupDisplayType: 'multipleColumns'` so each group level has its own header. Try the following to see per-level isolation:

- Sort `Athlete` or `Total` (leaf columns): only the rows inside each year group reorder; year and country groups keep their structural order.
- Sort the `Year` group column: only year groups within each country reorder; country groups stay structural.
- Sort the `Country` group column: only country groups reorder; year groups within each country keep their structural order.
- Clear a group-column sort: that level reverts to structural order; sibling levels are unaffected.

The structural order is the data-insertion order by default, or the order produced by [`initialGroupOrderComparator`](#unsorted-group-order) if one is configured. If a group column had a sort applied and the user later explicitly clears that sort, the structural order is restored.

## Unsorted Group Order

When no sorting is applied, the groups are ordered by the order in which they appear in the data. This order can be overwritten with a custom initial order by providing an `initialGroupOrderComparator` grid option.

> **Note**
>
> As this is an initial order of groups, it executes before filtering and aggregation. This means it cannot use post-filtered data, or aggregated values as comparison criteria.

#### Initial Group Order

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  InitialGroupOrderComparator,
  InitialGroupOrderComparatorParams,
  ModuleRegistry,
  RowGroupingDisplayType,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :autoGroupColumnDef="autoGroupColumnDef"
      :groupDisplayType="groupDisplayType"
      :initialGroupOrderComparator="initialGroupOrderComparator"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", rowGroup: true, hide: true },
      { field: "year", rowGroup: true, hide: true },
      { field: "athlete" },
      { field: "total" },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      minWidth: 100,
    });
    const autoGroupColumnDef = ref<AutoGroupColumnDef>({
      minWidth: 200,
    });
    const groupDisplayType = ref<RowGroupingDisplayType>("multipleColumns");
    const initialGroupOrderComparator = ref<InitialGroupOrderComparator>(
      (params: InitialGroupOrderComparatorParams) =>
        params.nodeA.allLeafChildren.length -
        params.nodeB.allLeafChildren.length,
    );
    const rowData = ref<any[]>(null);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      const updateData = (data) => (rowData.value = data);

      fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((data) => updateData(data));
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      autoGroupColumnDef,
      groupDisplayType,
      initialGroupOrderComparator,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Initial Group Order](https://www.ag-grid.com/examples/grouping-sorting/initial-group-order/vue3)

The example above demonstrates the following configuration to order group rows based on the number of leaf children:

```ts
<ag-grid-vue
    :initialGroupOrderComparator="initialGroupOrderComparator"
    /* other grid options ... */>
</ag-grid-vue>

this.initialGroupOrderComparator = (params) =>
    params.nodeA.allLeafChildren.length - params.nodeB.allLeafChildren.length;
```
