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

# Row Grouping - Row Dragging

Row dragging can be combined with [Row Grouping](https://www.ag-grid.com/vue-data-grid/grouping/). This page focuses on grouping-specific configuration; see the [Row Dragging](https://www.ag-grid.com/vue-data-grid/row-dragging/) overview for the general capabilities and limitations of the feature.

## Managed Row Dragging

[Managed Row Dragging](https://www.ag-grid.com/vue-data-grid/row-dragging-managed/) can update grouped data automatically. The grid moves the dragged rows or groups and updates the underlying row data.

In this example, users can drag athletes and groups of athletes between countries.

#### Managed Row Drag Across Regions

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  RowDragModule,
  RowSelectionModule,
  RowSelectionOptions,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { BatchEditModule, RowGroupingModule } from "ag-grid-enterprise";
import { getAthletesData } from "./data";
import { IAthlete } from "./types";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  RowGroupingModule,
  RowDragModule,
  RowSelectionModule,
  TextEditorModule,
  TextFilterModule,
  NumberEditorModule,
  NumberFilterModule,
  BatchEditModule,
]);

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"
      :animateRows="true"
      :groupDefaultExpanded="groupDefaultExpanded"
      :rowDragManaged="true"
      :suppressMoveWhenRowDragging="true"
      :refreshAfterGroupEdit="true"
      :rowDragMultiRow="true"
      :rowSelection="rowSelection"
      :getRowId="getRowId"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IAthlete> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", width: 120, rowGroup: true, editable: true },
      { field: "year", width: 90, rowGroup: true, editable: true },
      { field: "athlete", minWidth: 150 },
      { field: "age", minWidth: 50, filter: "agNumberColumnFilter" },
      { field: "date", width: 110 },
      { field: "sport", width: 110 },
      { field: "gold", width: 110 },
      { field: "silver", width: 110 },
      { field: "bronze", width: 110 },
    ]);
    const defaultColDef = ref<ColDef>({
      sortable: true,
      filter: true,
    });
    const autoGroupColumnDef = ref<AutoGroupColumnDef>({
      rowDrag: true,
      width: 250,
    });
    const groupDefaultExpanded = ref(-1);
    const rowSelection = ref<RowSelectionOptions | "single" | "multiple">({
      mode: "multiRow",
      headerCheckbox: false,
    });
    const getRowId = ref<GetRowIdFunc>(({ data }) => data.id);
    const rowData = ref<IAthlete[] | null>(getAthletesData());

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

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

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

[Live example: Managed Row Drag Across Regions](https://www.ag-grid.com/examples/grouping-row-dragging/managed-row-group-drag-multi-level/vue3)

## Configuration

When using managed row dragging with grouping the following configuration is required:

- `getRowId` is required to uniquely identify rows.
- `rowDragManaged=true` is needed to enable managed dragging.
- `refreshAfterGroupEdit=true` is required so the grid re-evaluates the groups immediately after a drag changes the grouped column values.
- `rowDrag=true` needs to be set in a column or in the auto group column definitions or the `rowDragEntireRow=true` in the grid options.
- `suppressMoveWhenRowDragging=true` to avoid the performance penalty of rebuilding the whole hierarchy while dragging and to avoid the grid reordering rows mid-drag, which otherwise causes large visual jumps when parent branches move.
- `BatchEditModule` is recommended, together with `TextEditorModule` (or your preferred editor modules) and to handle edit and batch edit events.
- Managed drag works only with [Client-Side Row Model](https://www.ag-grid.com/vue-data-grid/row-models/#client-side).

See [Editing Groups](https://www.ag-grid.com/vue-data-grid/grouping-edit/) for more on editing grouped data and `refreshAfterGroupEdit`.

## API Reference

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `rowDragManaged` | `boolean` |  | `false` | Set to `true` to enable Managed Row Dragging. Module: [`RowDragModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
| `suppressMoveWhenRowDragging` | `boolean` |  | `false` | Set to `true` to suppress moving rows while dragging the `rowDrag` waffle. This option highlights the position where the row will be placed and it will only move the row on mouse up. Module: [`RowDragModule`](https://www.ag-grid.com/vue-data-grid/modules/). |

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `refreshAfterGroupEdit` | `boolean` |  | `false` | When `true`, the grid re-evaluates the grouping hierarchy after editing a grouped column value, moving the row to the correct group instantly. Also enables managed row dragging to update grouped column values so rows can move between groups. Modules (any of): [`RowGroupingModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`TreeDataModule`](https://www.ag-grid.com/vue-data-grid/modules/). |

## Unmanaged Row Dragging with Groups

[Unmanaged Row Dragging](https://www.ag-grid.com/vue-data-grid/row-dragging-unmanaged/) can update the group membership in application code by handling the row drag events and mutating the data that drives the grid. This keeps all row models and grid features available because the grid simply emits events.

The example below shows unmanaged row dragging with [Row Grouping](https://www.ag-grid.com/vue-data-grid/grouping/) where the following can be noted:

- The **Athlete** column enables a drag handle only for leaf rows via the callback version of `rowDrag`.
- Because the grid does not manage reordering, dragging remains available even while sorting or filtering is applied.
- The example listens to `onRowDragMove` to change the `country` for the dragged row in real time, and uses `api.applyTransaction({ update: [...] })` to commit the change.
- The application can decide whether to update rows during the drag or after `rowDragEnd`, and can allow changes regardless of sort and filter state.

#### Unmanaged Row Drag with Grouping

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

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

const rowDrag = function (params: RowDragCallbackParams) {
  // only rows that are NOT groups should be draggable
  return !params.node.group;
};

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :groupDefaultExpanded="groupDefaultExpanded"
      :rowData="rowData"
      @row-drag-move="onRowDragMove"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "athlete", rowDrag: rowDrag },
      { field: "country", rowGroup: true },
      { field: "year", width: 100 },
      { field: "date" },
      { field: "sport" },
      { field: "gold" },
      { field: "silver" },
      { field: "bronze" },
    ]);
    const defaultColDef = ref<ColDef>({
      width: 170,
      filter: true,
    });
    const groupDefaultExpanded = ref(1);
    const rowData = ref<any[]>(null);

    function onRowDragMove(event: RowDragEndEvent) {
      const movingNode = event.node!;
      const overNode = event.overNode!;
      // find out what country group we are hovering over
      let groupCountry;
      if (overNode.group) {
        // if over a group, we take the group key (which will be the
        // country as we are grouping by country)
        groupCountry = overNode.key;
      } else {
        // if over a non-group, we take the country directly
        groupCountry = overNode.data.country;
      }
      const needToChangeParent = movingNode.data.country !== groupCountry;
      if (needToChangeParent) {
        const movingData = movingNode.data;
        movingData.country = groupCountry;
        gridApi.value!.applyTransaction({
          update: [movingData],
        });
        gridApi.value!.clearFocusedCell();
      }
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      params.api.setGridOption("rowData", getData());
    };

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

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

[Live example: Unmanaged Row Drag with Grouping](https://www.ag-grid.com/examples/grouping-row-dragging/unmanaged-row-group-drag/vue3)
