---
product: "AG Charts"
title: "Touch"
description: "AG Charts implements touch and multi-touch support, enabling interactivity across all devices."
framework: react
version: "14.2.0"
related:
    - title: "Accessibility"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/accessibility/"
    - title: "Localisation"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/localisation/"
    - title: "Series Highlighting"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/series-highlighting/"
    - title: "Tooltips"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/tooltips/"
    - title: "Animation"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/animation/"
    - title: "Context Menu"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/context-menu/"
    - title: "Crosshairs & Band Highlight"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/axes-crosshairs/"
    - title: "Data Selection"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/selection/"
    - title: "Flash On Update"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/flash-on-update/"
    - title: "Navigator"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/navigator/"
    - title: "Range Controls"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/range-controls/"
    - title: "Scrollbar"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/scrollbar/"
    - title: "Synchronization"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/sync/"
    - title: "Zoom"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/react/zoom/"
llms: "https://www.ag-grid.com/charts/archive/14.2.0/llms.txt"
---

# Touch

AG Charts implements touch and multi-touch support, enabling interactivity across all devices.

## Touch Options

All interactivity is available via touch input.

For example:

- Tap the series area to show [tooltips](https://www.ag-grid.com/charts/archive/14.2.0/react/tooltips/) and [crosshairs](https://www.ag-grid.com/charts/archive/14.2.0/react/axes-crosshairs/).
- Tap or double-tap to [toggle a legend item](https://www.ag-grid.com/charts/archive/14.2.0/react/legend/#series-visibility-toggling), [reset zoom](https://www.ag-grid.com/charts/archive/14.2.0/react/zoom/#double-click-to-reset), or press any of the UI buttons.
- Any click and double-click [events](https://www.ag-grid.com/charts/archive/14.2.0/react/events/) are also triggered by a tap or double-tap.
- Long tap to bring up the [context menu](https://www.ag-grid.com/charts/archive/14.2.0/react/context-menu/).
- Drag to [zoom the axes](https://www.ag-grid.com/charts/archive/14.2.0/react/zoom/#axis-zoom-controls), [pan a zoomed chart](https://www.ag-grid.com/charts/archive/14.2.0/react/zoom/#panning), or interact with [annotations](https://www.ag-grid.com/charts/archive/14.2.0/react/annotations/).
- Use [two finger pinch gestures](https://www.ag-grid.com/charts/archive/14.2.0/react/zoom/#two-finger-zoom-pan) to zoom in or out of a chart, and two finger drag to pan a zoomed chart.

## Single Finger Touch Dragging

By default, Single Finger Touch Drag events are handled like mouse drag events. To change the input handling behaviour of these events, use `touch.dragAction`.

#### Single Finger Touch Dragging

```tsx
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
  AgCartesianChartOptions,
  AgTouchOptions,
  AnimationModule,
  CandlestickSeriesModule,
  ContextMenuModule,
  CrosshairModule,
  LegendModule,
  ModuleRegistry,
  NumberAxisModule,
  OrdinalTimeAxisModule,
  ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  AnimationModule,
  CandlestickSeriesModule,
  CrosshairModule,
  LegendModule,
  NumberAxisModule,
  OrdinalTimeAxisModule,
  ZoomModule,
  ContextMenuModule,
]);

const ChartExample = () => {
  const [options, setOptions] = useState<AgCartesianChartOptions>({
    data: getData(1e3),
    animation: { enabled: false },
    touch: { dragAction: "none" },
    zoom: {
      enabled: true,
      enableAxisDragging: false,
    },
    initialState: {
      zoom: {
        ratioX: { start: 0.48, end: 0.52 },
        ratioY: { start: 0.15, end: 0.6 },
      },
    },
    series: [
      {
        type: "candlestick",
        xKey: "timestamp",
        lowKey: "low",
        highKey: "high",
        openKey: "open",
        closeKey: "close",
      },
    ],
  });

  const changeAction = (event: Event) => {
    const nextOptions = clone(options);

    const newAction = (event.target as HTMLInputElement).value as NonNullable<
      AgTouchOptions["dragAction"]
    >;
    if (nextOptions.touch) {
      nextOptions.touch.dragAction = newAction;
    }

    setOptions(nextOptions);
  };

  return (
    <Fragment>
      <div className="example-controls">
        <div className="controls-row">
          <span>Drag Action:</span>
          <div className="button-group" role="group" aria-label="Drag Action">
            <input
              type="radio"
              id="dragAction-none"
              name="drag-action"
              defaultValue="none"
              defaultChecked
              onChange={(event) => changeAction(event)}
            />
            <label htmlFor="dragAction-none">
              <code>'none'</code>
            </label>
            <input
              type="radio"
              id="dragAction-drag"
              name="drag-action"
              defaultValue="drag"
              onChange={(event) => changeAction(event)}
            />
            <label htmlFor="dragAction-drag">
              <code>'drag'</code>
            </label>
            <input
              type="radio"
              id="dragAction-hover"
              name="drag-action"
              defaultValue="hover"
              onChange={(event) => changeAction(event)}
            />
            <label htmlFor="dragAction-hover">
              <code>'hover'</code>
            </label>
          </div>
        </div>
      </div>

      <AgCharts options={options} />
    </Fragment>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
```

[Live example: Single Finger Touch Dragging](https://www.ag-grid.com/charts/archive/14.2.0/reactFunctionalTs/touch/examples/single-finger-touch-dragging/)

```js
{
    touch: {
        dragAction: 'drag' | 'hover' | 'none',
    },
}
```

In this example:

- `dragAction: 'none'` disables the chart's Single Finger input handling, scrolling the entire page.
- `dragAction: 'drag'` emulates mouse dragging, panning the viewport if possible.
- `dragAction: 'hover'` emulates mouse movements, updating the tooltip and highlighted node.

## Two Finger Zoom-Pan

By default, charts use two finger gestures to zoom and pan. To pass this gesture to the underlying page, set `enableTwoFingerZoom: false`.

#### Two Finger Zoom-Pan

```tsx
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
  AgCartesianChartOptions,
  AnimationModule,
  ContextMenuModule,
  CrosshairModule,
  LegendModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
  ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  AnimationModule,
  CrosshairModule,
  LegendModule,
  LineSeriesModule,
  NumberAxisModule,
  ZoomModule,
  ContextMenuModule,
]);

const ChartExample = () => {
  const [options, setOptions] = useState<AgCartesianChartOptions>({
    animation: { enabled: false },
    touch: {
      dragAction: "none",
    },
    zoom: {
      enableDoubleClickToReset: false,
      enableTwoFingerZoom: true,
    },
    initialState: {
      zoom: {
        ratioX: { start: 0.48, end: 0.52 },
        ratioY: { start: 0.21, end: 0.82 },
      },
    },
    tooltip: {
      enabled: false,
    },
    axes: {
      y: {
        type: "number",
        interval: {
          minSpacing: 80,
          maxSpacing: 120,
        },
      },
      x: {
        type: "number",
        nice: false,
        interval: {
          minSpacing: 80,
          maxSpacing: 120,
        },
        label: {
          autoRotate: false,
        },
      },
    },
    data: getData(),
    series: [
      {
        type: "line",
        xKey: "year",
        yKey: "spending",
      },
    ],
  });

  const toggleTwoFingerZoom = (event: Event) => {
    const nextOptions = clone(options);

    const enabled = (event.target as HTMLInputElement).value === "true";
    if (nextOptions.zoom) {
      nextOptions.zoom.enableTwoFingerZoom = enabled;
    }

    setOptions(nextOptions);
  };

  return (
    <Fragment>
      <div className="example-controls">
        <div className="controls-row">
          <span>Two Finger Zoom:</span>
          <div
            className="button-group"
            role="group"
            aria-label="Two Finger Zoom"
          >
            <input
              type="radio"
              id="two-finger-zoom-enabled"
              name="two-finger-zoom"
              defaultValue="true"
              defaultChecked
              onChange={(event) => toggleTwoFingerZoom(event)}
            />
            <label htmlFor="two-finger-zoom-enabled">Enabled</label>
            <input
              type="radio"
              id="two-finger-zoom-disabled"
              name="two-finger-zoom"
              defaultValue="false"
              onChange={(event) => toggleTwoFingerZoom(event)}
            />
            <label htmlFor="two-finger-zoom-disabled">Disabled</label>
          </div>
        </div>
      </div>

      <AgCharts options={options} />
    </Fragment>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
```

[Live example: Two Finger Zoom-Pan](https://www.ag-grid.com/charts/archive/14.2.0/reactFunctionalTs/touch/examples/two-finger-zoompan/)

```js
{
    zoom: {
        enableTwoFingerZoom: true | false,
    },
}
```

## Long Tap

Long Tapping the chart will open the [Context Menu](https://www.ag-grid.com/charts/archive/14.2.0/react/context-menu/), if available.

#### Long Tap

```tsx
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
  AgCartesianChartOptions,
  AnimationModule,
  CategoryAxisModule,
  ContextMenuModule,
  CrosshairModule,
  LegendModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
} from "ag-charts-enterprise";

ModuleRegistry.registerModules([
  AnimationModule,
  CategoryAxisModule,
  CrosshairModule,
  LegendModule,
  LineSeriesModule,
  NumberAxisModule,
  ContextMenuModule,
]);

const ChartExample = () => {
  const [options, setOptions] = useState<AgCartesianChartOptions>({
    title: {
      text: "Financial Performance Overview",
    },
    animation: { enabled: false },
    data: [
      {
        year: 2018,
        revenue: 120,
        expenses: 80,
        profit: 40,
        investments: 30,
        taxes: 20,
        dividends: 10,
        rAndD: 25,
      },
      {
        year: 2019,
        revenue: 140,
        expenses: 90,
        profit: 50,
        investments: 40,
        taxes: 25,
        dividends: 12,
        rAndD: 30,
      },
      {
        year: 2020,
        revenue: 160,
        expenses: 100,
        profit: 60,
        investments: 50,
        taxes: 30,
        dividends: 15,
        rAndD: 35,
      },
      {
        year: 2021,
        revenue: 180,
        expenses: 110,
        profit: 70,
        investments: 55,
        taxes: 35,
        dividends: 18,
        rAndD: 40,
      },
      {
        year: 2022,
        revenue: 200,
        expenses: 120,
        profit: 80,
        investments: 60,
        taxes: 40,
        dividends: 20,
        rAndD: 45,
      },
    ],
    series: [
      { type: "line", xKey: "year", yKey: "revenue", yName: "Revenue" },
      { type: "line", xKey: "year", yKey: "expenses", yName: "Expenses" },
      { type: "line", xKey: "year", yKey: "profit", yName: "Profit" },
      { type: "line", xKey: "year", yKey: "investments", yName: "Investments" },
      { type: "line", xKey: "year", yKey: "taxes", yName: "Taxes" },
      { type: "line", xKey: "year", yKey: "dividends", yName: "Dividends" },
      { type: "line", xKey: "year", yKey: "rAndD", yName: "R&D Spending" },
    ],
  });

  return (
    <Fragment>
      <div className="example-controls"></div>
      <AgCharts options={options} />
    </Fragment>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
```

[Live example: Long Tap](https://www.ag-grid.com/charts/archive/14.2.0/reactFunctionalTs/touch/examples/long-tap/)

## API Reference

#### Touch

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| dragAction | 'none' \| 'drag' \| 'hover' | 'drag' | Sets the input handling behaviour for single-finger touch drag events.  - `'none'` - ignores these events, typically causing the default page-scrolling behaviour. - `'hover'` - makes these behave like mouse hover events, showing tooltip and crosshairs. - `'drag'` - makes these behave like mouse drag events (moving while holding left-button). |
