---
title: "Cross Filter Chart API"
enterprise: true
framework: react
version: "36.1.0"
---

# Cross Filter Chart API

Cross-filtering charts allow users to interact with data in an easy and intuitive way. Clicking on chart elements automatically filters values in both the grid and other cross-filter charts.

> **Warning**
>
> Cross-filtering in AG Grid is no longer being actively developed. For interactive dashboards and a more powerful cross-filtering experience, check out our purpose-built dashboarding tool [AG Studio](https://www.ag-grid.com/studio/javascript/filters/#cross-filtering).

![Cross Filtering](https://www.ag-grid.com/archive/36.1.0/_astro/cross-filtering.Ced09ekD.gif)

This built-in feature of integrated charts is particularly useful for creating interactive reports and dashboards.

## Creating Cross-filter Charts

Cross-Filter charts are created programmatically using `createCrossFilterChart(params)` on the grid's API.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `createCrossFilterChart` | `Function` |  |  | Used to programmatically create cross filter charts from a range. Module: [`IntegratedChartsModule`](https://www.ag-grid.com/archive/36.1.0/react-data-grid/modules/). |

The following snippet shows how a cross-filtering pie chart can be created:

```jsx
gridApi.createCrossFilterChart({
    chartType: 'pie',
    cellRange: {
        columns: ['salesRep', 'sale'],
    },
    aggFunc: 'sum',
});
```

Note in the snippet above that the `sale` values are aggregated by the `salesRep` category as `aggFunc: 'sum'` is specified.

A corresponding column configuration for the chart above is shown in the following snippet:

```jsx
const [columnDefs, setColumnDefs] = useState([
    { field: 'salesRep', filter: 'agSetColumnFilter', chartDataType: 'category' },
    { field: 'sale', chartDataType: 'series' },
]);

<AgGridReact columnDefs={columnDefs} />
```

> **Note**
>
> Cross-filtering Charts only support Client-Side Row Model. Grid filtering needs to be enabled on the category column(s) with either a [Set Filter](https://www.ag-grid.com/archive/36.1.0/react-data-grid/filter-set/) or [Multi Filter](https://www.ag-grid.com/archive/36.1.0/react-data-grid/filter-multi/). It is also important to define the [Chart Data Type](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-range-chart/#coldefchartdatatype) as it's not possible to infer the type when all data is filtered out.

The following example shows how to create a simple cross-filtering pie chart. Note the following:

- **Click** on a sector of the pie chart to filter rows in the grid by the selected sales rep.
- **Ctrl (Cmd) Click** on another sector to additionally adds rows corresponding to the selected sales rep.
- **Click Chart Background** to remove / reset the filtering in the grid to restore all rows in the grid.

#### Simple Cross-Filter

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  IntegratedChartsModule,
  MultiFilterModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  SetFilterModule,
  RowGroupingModule,
];

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "salesRep", chartDataType: "category" },
    { field: "handset", chartDataType: "category" },
    { field: "sale", chartDataType: "series" },
    { field: "saleDate", chartDataType: "category" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      filter: "agSetColumnFilter",
      floatingFilter: true,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createCrossFilterChart({
      chartType: "pie",
      cellRange: {
        columns: ["salesRep", "sale"],
      },
      aggFunc: "sum",
      chartThemeOverrides: {
        common: {
          title: {
            enabled: true,
            text: "Sales by Representative ($)",
          },
        },
        pie: {
          series: {
            title: {
              enabled: false,
            },
            calloutLabel: {
              enabled: false,
            },
          },
          legend: {
            position: "right",
          },
        },
      },
      sort: false,
      chartContainer: document.querySelector("#pieChart") as any,
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div id="pieChart"></div>

          <div id="myGrid" style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              enableCharts={true}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Simple Cross-Filter](https://www.ag-grid.com/archive/36.1.0/examples/integrated-charts-api-cross-filter-chart/simple-cross-filter/reactFunctionalTs)

## Cross-filter API

The cross-filter api shares a similar api to [Range Chart](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-api-range-chart/), however there are different defaults which make sense for cross-filtering.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `createCrossFilterChart` | `Function` |  |  | Used to programmatically create cross filter charts from a range. Module: [`IntegratedChartsModule`](https://www.ag-grid.com/archive/36.1.0/react-data-grid/modules/). |

Properties available on the `CreateCrossFilterChartParams` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `chartType` | `CrossFilterChartType` | Yes |  | The type of cross-filtering chart to create. |
| `cellRange` | `ChartParamsCellRange` | Yes |  | Defines the list of columns to be charted. Note that cross-filter charts include all rows in the grid so there is no need to specify the range of rows. |
| `suppressChartRanges` | `boolean` |  | `true` | By default, when a cross-filter chart is displayed using the grid, the grid will not highlight the range the chart is charting when the chart gets focus. To show the chart range set `suppressChartRanges=false`. |
| `aggFunc` | [`string \| IAggFunc`](https://www.ag-grid.com/archive/36.1.0/react-data-grid/aggregation-custom-functions/) |  |  | The aggregation function that should be applied to all series data. The built-in aggregation functions are `'sum'`, `'min'`, `'max'`, `'count'`, `'avg'`, `'first'`, `'last'`. Alternatively, custom aggregation functions can be provided if they conform to the `IAggFunc` interface shown here. |
| `sort` | `SortModelItem[] \| boolean` |  | `true` | By default (or when `true`), the order in cross filter charts will match grid sorting. Set to `false` to disable sorting for this chart. Set to a `SortModelItem[]` to provide a custom sorting for this chart. |
| `chartThemeName` | `string` |  |  | The default theme to use for the created chart. In addition to the default options you listed, you can also provide your own [custom chart themes](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-customisation/#custom-chart-themes). Options: `'ag-default'`, `'ag-default-dark'`, `'ag-material'`, `'ag-material-dark'`, `'ag-pastel'`, `'ag-pastel-dark'`, `'ag-vivid'`, `'ag-vivid-dark'`, `'ag-solar'`, `'ag-solar-dark'`. |
| `chartContainer` | [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) |  |  | If the chart is to be displayed outside of the grid then a chart container should be provided. If the chart is to be displayed using the grid's popup window mechanism then leave as `undefined`. |
| `chartThemeOverrides` | [`AgChartThemeOverrides`](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides) |  |  | Allows specific chart options in the current theme to be overridden. See [Overriding Existing Themes](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-customisation/#overriding-themes) for more information. |
| `unlinkChart` | `boolean` |  | `false` | When enabled the chart will be unlinked from the grid after creation, any updates to the data will not be reflected in the chart. See [Unlinking Charts](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-menu/#default-chart-menu-items) for more information. |

## Cross-filter Chart Types

The following examples show the different chart types that support cross-filtering:

### Example: Sales Dashboard #1

#### Sales Dashboard

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  DateEditorModule,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  TextEditorModule,
  TextFilterModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  IntegratedChartsModule,
  MultiFilterModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  SetFilterModule,
  RowGroupingModule,
  NumberFilterModule,
  TextFilterModule,
  TextEditorModule,
  DateEditorModule,
  NumberEditorModule,
];

function createQuarterlySalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "column",
    cellRange: {
      columns: ["quarter", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Quarterly Sales ($)",
        },
        legend: { enabled: false },
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
          number: {
            label: {
              formatter: (params: any) => {
                return params.value / 1000 + "k";
              },
            },
          },
        },
      },
    },
    sort: [{ colId: "quarter", sort: "asc" }],
    chartContainer: document.querySelector("#columnChart") as any,
  });
}

function createSalesByRefChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "pie",
    cellRange: {
      columns: ["salesRep", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Sales by Representative ($)",
        },
      },
      pie: {
        series: {
          title: {
            enabled: false,
          },
          calloutLabel: {
            enabled: false,
          },
        },
        legend: {
          position: "right",
        },
      },
    },
    sort: false,
    chartContainer: document.querySelector("#pieChart") as any,
  });
}

function createHandsetSalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "bar",
    cellRange: {
      columns: ["handset", "sale"],
    },
    aggFunc: "count",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Handsets Sold (Units)",
        },
        legend: { enabled: false },
      },
    },
    sort: [{ colId: "handset", sort: "asc" }],
    chartContainer: document.querySelector("#barChart") as any,
  });
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "salesRep", chartDataType: "category" },
    { field: "handset", chartDataType: "category" },
    {
      headerName: "Sale Price",
      field: "sale",
      maxWidth: 160,
      aggFunc: "sum",
      filter: "agNumberColumnFilter",
      chartDataType: "series",
    },
    {
      field: "saleDate",
      chartDataType: "category",
      filter: "agSetColumnFilter",
      filterParams: {
        valueFormatter: (params: ValueFormatterParams) => `${params.value}`,
      },
      sort: "asc",
    },
    {
      field: "quarter",
      maxWidth: 160,
      filter: "agSetColumnFilter",
      chartDataType: "category",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      editable: true,
      filter: "agMultiColumnFilter",
      floatingFilter: true,
    };
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      bar: {
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    createQuarterlySalesChart(params.api);
    createSalesByRefChart(params.api);
    createHandsetSalesChart(params.api);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div id="columnChart"></div>
          <div id="pieChart"></div>
          <div id="barChart"></div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Sales Dashboard](https://www.ag-grid.com/archive/36.1.0/examples/integrated-charts-api-cross-filter-chart/sales-dashboard/reactFunctionalTs)

### Example: Sales Dashboard #2

#### Sales Dashboard 2

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  DateEditorModule,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  TextEditorModule,
  TextFilterModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  IntegratedChartsModule,
  MultiFilterModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  SetFilterModule,
  RowGroupingModule,
  NumberFilterModule,
  TextFilterModule,
  NumberEditorModule,
  TextEditorModule,
  DateEditorModule,
];

function createQuarterlySalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "line",
    cellRange: {
      columns: ["quarter", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Quarterly Sales ($)",
        },
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
          number: {
            label: {
              formatter: (params: any) => {
                return params.value / 1000 + "k";
              },
            },
          },
        },
      },
    },
    sort: [{ colId: "quarter", sort: "asc" }],
    chartContainer: document.querySelector("#lineChart") as any,
  });
}

function createSalesByRefChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "donut",
    cellRange: {
      columns: ["salesRep", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Sales by Representative ($)",
        },
      },
      pie: {
        legend: {
          position: "right",
        },
        series: {
          title: {
            enabled: false,
          },
          calloutLabel: {
            enabled: false,
          },
        },
      },
    },
    sort: false,
    chartContainer: document.querySelector("#donutChart") as any,
  });
}

function createHandsetSalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "area",
    cellRange: {
      columns: ["handset", "sale"],
    },
    aggFunc: "count",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Handsets Sold (Units)",
        },
        padding: { left: 47, right: 80 },
      },
    },
    sort: [{ colId: "handset", sort: "asc" }],
    chartContainer: document.querySelector("#areaChart") as any,
  });
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "salesRep", chartDataType: "category" },
    { field: "handset", chartDataType: "category" },
    {
      headerName: "Sale Price",
      field: "sale",
      maxWidth: 160,
      aggFunc: "sum",
      filter: "agNumberColumnFilter",
      chartDataType: "series",
    },
    {
      field: "saleDate",
      chartDataType: "category",
      filter: "agSetColumnFilter",
      filterParams: {
        valueFormatter: (params: ValueFormatterParams) => `${params.value}`,
      },
      sort: "asc",
    },
    {
      field: "quarter",
      maxWidth: 160,
      filter: "agSetColumnFilter",
      chartDataType: "category",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      editable: true,
      filter: "agMultiColumnFilter",
      floatingFilter: true,
    };
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      bar: {
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    createQuarterlySalesChart(params.api);
    createSalesByRefChart(params.api);
    createHandsetSalesChart(params.api);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div id="lineChart"></div>
          <div id="donutChart"></div>
          <div id="areaChart"></div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Sales Dashboard 2](https://www.ag-grid.com/archive/36.1.0/examples/integrated-charts-api-cross-filter-chart/sales-dashboard2/reactFunctionalTs)

### Example: Most Populous Cities

#### Most Populous Cities

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  IntegratedChartsModule,
  MultiFilterModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  SetFilterModule,
  RowGroupingModule,
  TextFilterModule,
  TextEditorModule,
  NumberFilterModule,
  NumberEditorModule,
];

function createColumnChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "column",
    cellRange: {
      columns: ["country", "population"],
    },
    aggFunc: "count",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Number of Most Populous Cities by Country",
        },
        legend: {
          enabled: false,
        },
      },
      bar: {
        axes: {
          category: {
            label: {
              rotation: 325,
            },
          },
        },
      },
    },
    sort: [{ colId: "country", sort: "asc" }],
    chartContainer: document.querySelector("#barChart") as any,
  });
}

function createBubbleChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "bubble",
    cellRange: {
      columns: ["longitude", "latitude", "population"],
    },
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Latitude vs Longitude of Most Populous Cities",
        },
        legend: {
          enabled: false,
        },
      },
    },
    sort: false,
    chartContainer: document.querySelector("#bubbleChart") as any,
  });
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "city", chartDataType: "category" },
    { field: "country", chartDataType: "category" },
    { field: "longitude", chartDataType: "series" },
    { field: "latitude", chartDataType: "series" },
    { field: "population", chartDataType: "series" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      editable: true,
      filter: "agMultiColumnFilter",
      floatingFilter: true,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    createColumnChart(params.api);
    createBubbleChart(params.api);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div id="barChart"></div>
          <div id="bubbleChart"></div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              enableCharts={true}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Most Populous Cities](https://www.ag-grid.com/archive/36.1.0/examples/integrated-charts-api-cross-filter-chart/most-populous-cities/reactFunctionalTs)

### Example: Custom Theme

In this example, we use a custom theme to style the charts using `customChartTheme` and `chartTheme`. See the [Custom Chart Themes](https://www.ag-grid.com/archive/36.1.0/react-data-grid/integrated-charts-customisation/#custom-chart-themes) section for more information.

> **Note**
>
> Note that for cosmetic changes in cross-filtering charts, you must use a custom theme. Cross-filtering charts rely on a theme to derive filtered value colours from existing theme colours. Specifying your own colours in the theme overrides will disable this behaviour.

#### Custom Theme

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  CustomChartThemes,
  DateEditorModule,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  TextEditorModule,
  TextFilterModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  IntegratedChartsModule,
  MultiFilterModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData, phones } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  SetFilterModule,
  RowGroupingModule,
  NumberFilterModule,
  TextFilterModule,
  TextEditorModule,
  DateEditorModule,
  NumberEditorModule,
];

function createQuarterlySalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "column",
    cellRange: {
      columns: ["quarter", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Quarterly Sales ($)",
        },
        legend: { enabled: false },
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
          number: {
            label: {
              formatter: (params: any) => {
                return params.value / 1000 + "k";
              },
            },
          },
        },
      },
    },
    sort: [{ colId: "quarter", sort: "asc" }],
    chartContainer: document.querySelector("#columnChart") as any,
  });
}

function createSalesByRefChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "pie",
    cellRange: {
      columns: ["salesRep", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Sales by Representative ($)",
        },
      },
      pie: {
        series: {
          title: {
            enabled: false,
          },
          calloutLabel: {
            enabled: false,
          },
        },
        legend: {
          position: "right",
        },
      },
    },
    sort: false,
    chartContainer: document.querySelector("#pieChart") as any,
  });
}

function createHandsetSalesChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "area",
    cellRange: {
      columns: ["handset", "sale"],
    },
    aggFunc: "count",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Handsets Sold (Units)",
        },
        padding: { left: 47, right: 80 },
      },
    },
    sort: [{ colId: "handset", sort: "asc" }],
    chartContainer: document.querySelector("#areaChart") as any,
  });
}

function createBubbleChart(api: GridApi) {
  api.createCrossFilterChart({
    chartType: "bubble",
    cellRange: {
      columns: ["quarterIndex", "handsetIndex", "sale"],
    },
    aggFunc: "sum",
    chartThemeOverrides: {
      common: {
        title: {
          enabled: true,
          text: "Sales by Quarter and Handset",
        },
        legend: {
          enabled: false,
        },
        seriesArea: {
          padding: {
            left: 8,
            bottom: 8,
          },
        },
        axes: {
          number: {
            label: {
              formatter: (params: any) => {
                // For this example only: format two number series differently with a single formatter
                if (params.value < 10) {
                  if (Math.floor(params.value) !== params.value) {
                    return "";
                  }
                  return `Q${params.value}`;
                } else {
                  return phones[params.value - 10]?.handset ?? "";
                }
              },
            },
            nice: false,
          },
        },
      },
    },
    sort: false,
    chartContainer: document.querySelector("#bubbleChart") as any,
  });
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "salesRep", chartDataType: "category" },
    { field: "handset", chartDataType: "category" },
    { field: "handsetIndex", chartDataType: "series", hide: true },
    { field: "quarterIndex", chartDataType: "series", hide: true },
    {
      headerName: "Sale Price",
      field: "sale",
      maxWidth: 160,
      aggFunc: "sum",
      filter: "agNumberColumnFilter",
      chartDataType: "series",
    },
    {
      field: "saleDate",
      chartDataType: "category",
      filter: "agSetColumnFilter",
      filterParams: {
        valueFormatter: (params: ValueFormatterParams) => `${params.value}`,
      },
      sort: "asc",
    },
    {
      field: "quarter",
      maxWidth: 160,
      filter: "agSetColumnFilter",
      chartDataType: "category",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      editable: true,
      filter: "agMultiColumnFilter",
      floatingFilter: true,
    };
  }, []);
  const customChartThemes = useMemo<CustomChartThemes>(() => {
    return {
      "my-custom-theme-light": {
        palette: {
          fills: [
            "purple",
            "indigo",
            "blue",
            "green",
            "yellow",
            "orange",
            "red",
          ],
        },
      },
      "my-custom-theme-dark": {
        palette: {
          fills: [
            "red",
            "orange",
            "yellow",
            "green",
            "blue",
            "indigo",
            "purple",
          ],
          strokes: ["white"],
        },
        overrides: {
          common: {
            title: {
              color: "white",
            },
            axes: {
              category: {
                label: {
                  color: "white",
                },
              },
              number: {
                label: {
                  color: "white",
                },
              },
            },
            legend: {
              item: {
                label: {
                  color: "white",
                },
              },
            },
          },
        },
      },
    };
  }, []);
  const chartThemes = useMemo<string[]>(() => {
    return ["my-custom-theme-light", "my-custom-theme-dark"];
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        background: {
          fill: "transparent",
        },
        zoom: {
          enabled: false,
        },
        axes: {
          number: {
            crosshair: {
              enabled: false,
            },
          },
          category: {
            crosshair: {
              enabled: false,
            },
          },
        },
      },
      bar: {
        axes: {
          category: {
            label: {
              rotation: 0,
            },
          },
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    createQuarterlySalesChart(params.api);
    createSalesByRefChart(params.api);
    createHandsetSalesChart(params.api);
    createBubbleChart(params.api);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div id="charts">
            <div id="columnChart"></div>
            <div id="pieChart"></div>
            <div id="areaChart"></div>
            <div id="bubbleChart"></div>
          </div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              enableCharts={true}
              customChartThemes={customChartThemes}
              chartThemes={chartThemes}
              chartThemeOverrides={chartThemeOverrides}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Custom Theme](https://www.ag-grid.com/archive/36.1.0/examples/integrated-charts-api-cross-filter-chart/custom-theme/reactFunctionalTs)
