---
title: "Touch"
framework: vue
version: "36.1.0"
---

# Touch

AG Grid is designed to work on touch devices. By default, browsers convert tap events to mouse click events. This means, for example, if you tap on a cell in AG Grid, the cell will get selected just like you clicked on the cell with a mouse. The remainder of this page explains touch gestures understood by the grid which are NOT simply the grid reacting to taps as mouse clicks. They are touch gestures coded into the grid.

## Touch Gestures for AG Grid Community

The following touch gestures are supported by AG Grid Community:

- Move columns by touch-dragging the column header with a touch.
- Move column groups by touch-dragging the column group header with a touch.
- Tap the column header to sort by that column.
- Tap and drag the column header resize handle to resize it

#### Touch Community

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ClientSideRowModelModule]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<(ColDef | ColGroupDef)[]>([
      { field: "athlete", minWidth: 200 },
      { field: "year" },
      { field: "sport" },
      {
        headerName: "Medals",
        children: [{ field: "gold" }, { field: "silver" }, { field: "bronze" }],
      },
    ]);
    const defaultColDef = ref<ColDef>({
      minWidth: 100,
      flex: 1,
    });
    const rowData = ref<IOlympicData[]>(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,
      rowData,
      onGridReady,
    };
  },
});

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

[Live example: Touch Community](https://www.ag-grid.com/examples/touch/touch-community/vue3)

## Touch Gestures for AG Grid Enterprise

The following touch gestures are support by AG Grid Enterprise (in addition to the AG Grid Community gestures mentioned above):

- Drag columns out of the tool panel using drag.
- Drag columns out of the row group and pivot drop zones by dragging.

#### Touch Enterprise

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  PivotModule,
  RowGroupingPanelModule,
  ColumnsToolPanelModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :sideBar="sideBar"
      :allowDragFromColumnsToolPanel="true"
      :pivotMode="true"
      :rowGroupPanelShow="rowGroupPanelShow"
      :pivotPanelShow="pivotPanelShow"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "country", rowGroup: true },
      { field: "sport", pivot: true },
      { field: "year", pivot: true },
      { field: "gold", aggFunc: "sum" },
    ]);
    const defaultColDef = ref<ColDef>({
      minWidth: 100,
      enableValue: true,
      enableRowGroup: true,
      enablePivot: true,
    });
    const sideBar = ref<SideBarDef | string | string[] | boolean | null>(
      "columns",
    );
    const rowGroupPanelShow = ref<"always" | "onlyWhenGrouping" | "never">(
      "always",
    );
    const pivotPanelShow = ref<"always" | "onlyWhenPivoting" | "never">(
      "always",
    );
    const rowData = ref<IOlympicData[]>(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,
      sideBar,
      rowGroupPanelShow,
      pivotPanelShow,
      rowData,
      onGridReady,
    };
  },
});

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

[Live example: Touch Enterprise](https://www.ag-grid.com/examples/touch/touch-enterprise/vue3)

## Enabling Double Clicking on Mobile Devices

The default behaviour on many mobile devices when a page is double clicked on it to zoom in. To prevent this behaviour so that a double click would, for example, edit a cell you need to disable viewport zooming.

You can disable viewport zooming by setting the following tag at the top level page:

```html
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

## Column Menu Touch Configuration

By default, the Column Menu is launched from the menu button in the header. However, there are some situations where the menu button is not displayed. In these cases, the menu can be launched via tap and hold (for 500 ms) on the header.

The following example demonstrates these different scenarios:

- The `Athlete` column has the default behaviour where the menu is launched via a button.
- The `Country` column has `colDef.suppressHeaderMenuButton = true` set. The menu button is suppressed, and the menu is launched via tap and hold.
- The `Sport` column has `colDef.suppressHeaderMenuButton = true` and `colDef.suppressHeaderContextMenu = true` set. Both the menu button, and tap and hold are suppressed.
- The `Medals` column group has no menu button as it is a column group not a column. The menu is launched via tap and hold.

#### Column Menu New

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

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnMenuModule,
  ColumnAutoSizeModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<(ColDef | ColGroupDef)[]>([
      { field: "athlete" },
      {
        field: "country",
        suppressHeaderMenuButton: true,
      },
      {
        field: "sport",
        suppressHeaderMenuButton: true,
        suppressHeaderContextMenu: true,
      },
      {
        headerName: "Medals",
        children: [{ field: "gold" }],
      },
    ]);
    const defaultColDef = ref<ColDef>({
      minWidth: 100,
      flex: 1,
    });
    const rowData = ref<IOlympicData[]>(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,
      rowData,
      onGridReady,
    };
  },
});

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

[Live example: Column Menu New](https://www.ag-grid.com/examples/touch/column-menu-new/vue3)

If `suppressMenuHide = false`, the menu will behave the same as the [Legacy Tabbed Column Menu](#legacy-tabbed-column-menu) described below.

### Legacy Tabbed Column Menu

If the [Legacy Tabbed Column Menu](https://www.ag-grid.com/vue-data-grid/column-menu/#legacy-tabbed-column-menu) is enabled, the column menu icon is hidden by default and only appears on mouseover. On touch devices, this mouseover behaviour is not possible, so it is displayed via tap and hold on the column header.

#### Column Menu Legacy

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

ModuleRegistry.registerModules([ClientSideRowModelModule, ColumnMenuModule]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :columnMenu="columnMenu"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "athlete", minWidth: 200 },
      { field: "age" },
      { field: "country", minWidth: 200 },
      { field: "year" },
      { field: "sport" },
      { field: "gold" },
      { field: "silver" },
      { field: "bronze" },
    ]);
    const defaultColDef = ref<ColDef>({
      minWidth: 100,
      flex: 1,
    });
    const columnMenu = ref<"legacy" | "new">("legacy");
    const rowData = ref<IOlympicData[]>(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,
      columnMenu,
      rowData,
      onGridReady,
    };
  },
});

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

[Live example: Column Menu Legacy](https://www.ag-grid.com/examples/touch/column-menu/vue3)

### Suppress Menu Hide

If you are using the legacy column menu and need a visual indicator to inform the user that a menu exists, you can set the grid option `suppressMenuHide = true`. Note that when this is enabled, the default tap and hold behaviour will no longer apply, and the column menu icon must be tapped instead.

The following example demonstrates suppressing the menu hide behaviour:

#### Column Menu Suppress Hide

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

ModuleRegistry.registerModules([ClientSideRowModelModule, ColumnMenuModule]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :defaultColDef="defaultColDef"
      :suppressMenuHide="true"
      :columnMenu="columnMenu"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "athlete", minWidth: 200 },
      { field: "age" },
      { field: "country", minWidth: 200 },
      { field: "year" },
      { field: "sport" },
      { field: "gold" },
      { field: "silver" },
      { field: "bronze" },
    ]);
    const defaultColDef = ref<ColDef>({
      minWidth: 100,
      flex: 1,
    });
    const columnMenu = ref<"legacy" | "new">("legacy");
    const rowData = ref<IOlympicData[]>(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,
      columnMenu,
      rowData,
      onGridReady,
    };
  },
});

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

[Live example: Column Menu Suppress Hide](https://www.ag-grid.com/examples/touch/column-menu-suppress-menu-hide/vue3)

## Custom Header Components

If using custom header components with interactive elements, the grid may consume the touch events in order to support the behaviour above. To prevent this, either the grid touch support can be disabled by setting the grid option `suppressTouch = true`, or the custom header component can stop propagation on the `touchstart` event.
