---
title: "Chart Customisation"
enterprise: true
framework: react
version: "36.1.0"
---

# Chart Customisation

Integrated Charts can be customised via the [AG Charts Theme API](https://www.ag-grid.com/charts/themes-api/).

## Provided Themes

The following themes are provided to Integrated Charts by default.

```js
['ag-default', 'ag-material', 'ag-sheets', 'ag-polychroma', 'ag-vivid']
```

These themes correspond to [AG Charts Base Themes](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-baseTheme).

> **Note**
>
> When using a dark colour scheme for the grid, the application must provide the dark equivalents of the chart themes. If a default AG Chart theme is used, the dark themes are named with a `-dark` suffix, e.g. `'ag-vivid-dark'`.

The selected theme can be changed by the user via the [Chart Tool Panel](https://www.ag-grid.com/react-data-grid/integrated-charts-chart-tool-panels/) or by changing the order of the provided themes using the `chartThemes` grid option as shown below:

```jsx
const chartThemes = ['ag-vivid', 'ag-polychroma', 'ag-material', 'ag-sheets', 'ag-default'];

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

## Overriding Themes

Integrated Charts uses a theme based configuration which 'overrides' the theme defaults.

To override a charts theme, use the `chartsThemeOverrides` grid option.

```jsx
const chartThemeOverrides = useMemo(() => { 
	return {
        common: {
            title: {
                fontSize: 22,
                fontFamily: 'Arial, sans-serif'
            }
        }
    };
}, []);

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

> **Note**
>
> Note that the `chartThemeOverrides` grid option maps to [AG Charts Theme Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides).

### Common Overrides

These overrides can be used with any series type. For full list of overrides see [Common Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-common) in the AG Charts documentation.

#### Common Overrides

```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,
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

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

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnMenuModule,
  ContextMenuModule,
  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: "country", width: 150, chartDataType: "category" },
    { field: "gold", chartDataType: "series" },
    { field: "silver", chartDataType: "series" },
    { field: "bronze", chartDataType: "series" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        title: {
          enabled: true,
          text: "Precious Metals Production",
        },
        subtitle: {
          enabled: true,
          text: "by country",
          fontSize: 14,
          fontFamily: "Monaco, monospace",
          color: "#aaa",
          spacing: 10,
        },
        padding: {
          left: 80,
          right: 80,
        },
        legend: {
          spacing: 30,
          item: {
            label: {
              fontStyle: "italic",
              fontWeight: "bold",
              fontSize: 18,
              fontFamily: "Palatino, serif",
              color: "#aaa",
            },
            marker: {
              shape: "circle",
              size: 10,
              padding: 10,
              strokeWidth: 2,
            },
            padding: {
              left: 15,
              right: 15,
            },
          },
        },
      },
    };
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createRangeChart({
      cellRange: {
        rowStartIndex: 0,
        rowEndIndex: 3,
        columns: ["country", "gold", "silver", "bronze"],
      },
      chartType: "groupedColumn",
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            ref={gridRef}
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            popupParent={popupParent}
            cellSelection={true}
            enableCharts={true}
            chartThemeOverrides={chartThemeOverrides}
            onGridReady={onGridReady}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Common Overrides](https://www.ag-grid.com/examples/integrated-charts-customisation/common-overrides/reactFunctionalTs)

### Chart-specific Overrides

The following documentation links describe different types of overrides specific to individual AG Charts series types.

- [Line Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-line)
- [Bar Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-bar)
- [Area Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-area)
- [Scatter Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-scatter)
- [Pie Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-pie)
- [Radar Line Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-radar-line)
- [Radar Area Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-radar-area)
- [Nightingale Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-nightingale)
- [Radial Column Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-radial-column)
- [Radial Bar Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-radial-bar)
- [Range Bar Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-range-bar)
- [Range Area Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-range-area)
- [Box Plot Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-box-plot)
- [Waterfall Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-waterfall)
- [Heatmap Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-heatmap)
- [Treemap Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-treemap)
- [Sunburst Overrides](https://www.ag-grid.com/charts/themes-api/#reference-AgChartTheme-overrides-sunburst)

## Custom Chart Themes

Custom [AG Charts Themes](https://www.ag-grid.com/charts/react/themes/) can also be supplied to the grid via the `customChartThemes` grid option.

```jsx
const customChartThemes = useMemo(() => { 
	return {
        myCustomTheme: {
            palette: {
                fills: ['#42a5f5', '#ffa726', '#81c784'],
                strokes: ['#000000', '#424242'],
            },
            overrides: {
                common: {
                    background: {
                        fill: '#f4f4f4',
                    },
                    legend: {
                        item: {
                            label: {
                                color: '#333333',
                            },
                        },
                    },
                },
            },
        },
        chartThemes: ['myCustomTheme', 'ag-vivid'],
    };
}, []);

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

The example below shows a custom chart theme being used with the grid. Note that other provided themes can be used alongside a custom theme, and are unaffected by the settings in the custom theme.

#### Custom Chart 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 {
  AgChartsEnterpriseModule,
  AgThemeOverrides,
} from "ag-charts-enterprise";
import {
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  CustomChartThemes,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { deepMerge, getData } from "./data";

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

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

const commonThemeProperties: {
  overrides: AgThemeOverrides;
} = {
  overrides: {
    common: {
      legend: {
        position: "top",
        spacing: 25,
        item: {
          label: {
            fontStyle: "italic",
            fontWeight: "bold",
            fontSize: 18,
            fontFamily: "Palatino, serif",
          },
          marker: {
            shape: "circle",
            size: 14,
            padding: 8,
            strokeWidth: 2,
          },
        },
      },
    },
    bar: {
      axes: {
        number: {
          line: {
            width: 4,
          },
        },
        category: {
          line: {
            width: 2,
          },
          label: {
            rotation: 0,
          },
        },
      },
    },
  },
};

const myCustomOverridesLight: {
  overrides: AgThemeOverrides;
} = {
  overrides: {
    common: {
      background: {
        fill: "#f4f4f4",
      },
      legend: {
        item: {
          label: {
            color: "#333333",
          },
        },
      },
    },
    bar: {
      axes: {
        number: {
          bottom: {
            line: {
              stroke: "#424242",
            },
            label: {
              color: "#555555",
              fontStyle: "italic",
              fontWeight: "bold",
              fontSize: 12,
              spacing: 5,
            },
          },
        },
        category: {
          left: {
            line: {
              stroke: "#424242",
            },
            label: {
              color: "#555555",
              fontStyle: "italic",
              fontWeight: "bold",
              fontSize: 14,
              spacing: 8,
            },
          },
        },
      },
    },
  },
};

const myCustomThemeLight = deepMerge(commonThemeProperties, {
  palette: {
    fills: ["#42a5f5", "#ffa726", "#81c784"],
    strokes: ["#000000", "#424242"],
  },
  ...myCustomOverridesLight,
});

const myCustomOverridesDark: {
  overrides: AgThemeOverrides;
} = {
  overrides: {
    common: {
      background: {
        fill: "#15181c",
      },
      legend: {
        item: {
          label: {
            color: "#ECEFF1",
          },
        },
      },
    },
    bar: {
      axes: {
        number: {
          bottom: {
            line: {
              stroke: "#757575",
            },
            label: {
              color: "#B0BEC5",
              fontStyle: "italic",
              fontWeight: "bold",
              fontSize: 12,
              spacing: 5,
            },
          },
        },
        category: {
          left: {
            line: {
              stroke: "#757575",
            },
            label: {
              color: "#B0BEC5",
              fontStyle: "italic",
              fontWeight: "bold",
              fontSize: 14,
              spacing: 8,
            },
          },
        },
      },
    },
  },
};

const myCustomThemeDark = deepMerge(commonThemeProperties, {
  palette: {
    fills: ["#42a5f5", "#ffa726", "#81c784"],
    strokes: ["#ffffff", "#B0BEC5"],
  },
  ...myCustomOverridesDark,
});

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: "country", width: 150, chartDataType: "category" },
    { field: "gold", chartDataType: "series" },
    { field: "silver", chartDataType: "series" },
    { field: "bronze", chartDataType: "series" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemes = useMemo<string[]>(() => {
    return ["my-custom-theme-light", "my-custom-theme-dark"];
  }, []);
  const customChartThemes = useMemo<CustomChartThemes>(() => {
    return {
      "my-custom-theme-light": myCustomThemeLight,
      "my-custom-theme-dark": myCustomThemeDark,
    };
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createRangeChart({
      cellRange: {
        rowStartIndex: 0,
        rowEndIndex: 4,
        columns: ["country", "gold", "silver", "bronze"],
      },
      chartType: "groupedBar",
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            ref={gridRef}
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            popupParent={popupParent}
            cellSelection={true}
            enableCharts={true}
            chartThemes={chartThemes}
            customChartThemes={customChartThemes}
            onGridReady={onGridReady}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Custom Chart Theme](https://www.ag-grid.com/examples/integrated-charts-customisation/custom-chart-theme/reactFunctionalTs)

## Formatting

Chart values can be formatted in several different ways.

### Label Formatting

> **Note**
>
> The `valueFormatter` is not automatically applied to the chart axes. If you wish to use the grid's value formatters, you must apply them manually.

Custom label formatting can be applied to the chart axes by providing suitable formatters.

```jsx
const chartThemeOverrides = useMemo(() => { 
	return {
        common: {
            axes: {
                number: {
                    label: {
                        formatter: function(params) {
                            // prefix with dollar sign
                            return '$' + params.value;
                        },
                    },
                },
            },
        },
    };
}, []);

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

The example below shows:

- A custom label formatter being used with the vertical axis to display SI units for the data. Additionally, this example demonstrates the use of the `domain` property passed through to the formatter to provide a consistent scale across the value range.
- A custom title formatter using `boundSeries` property passed through to the formatter for the vertical axis to display which series the axes are representing.

#### Label Formatting

```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 {
  AgAxisCaptionFormatterParams,
  AgAxisLabelFormatterParams,
  AgChartsEnterpriseModule,
} from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { data } from "./data";

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

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

const titleFormatter = (params: AgAxisCaptionFormatterParams) =>
  `Power (${params.boundSeries.map((s) => s.name).join(", ")})`;

function createSIFormatter(units = "", precision = 0) {
  const SI_UNITS = ["", "K", "M", "G"];
  let tier: number | undefined;
  const calculateSITier: (domain: number[]) => number = (domain: number[]) => {
    const [min, max] = domain;
    const value = Math.max(Math.abs(min), Math.abs(max));
    return Math.floor(Math.log10(Math.abs(value)) / 3);
  };
  function formatSI(value: number, tier: number, precision: number) {
    if (value === 0) {
      return "0";
    }
    const suffix = SI_UNITS[tier] || "";
    const scaled = value / 10 ** (tier * 3);
    return `${scaled.toFixed(precision)}${suffix}${units}`;
  }
  return (params: AgAxisLabelFormatterParams) => {
    tier ??= calculateSITier(params.domain);
    return formatSI(params.value as number, tier, precision);
  };
}

const siFormatter = createSIFormatter("W", 2);

const isEfficiencySeries = (params: any) =>
  params.boundSeries.find((s: any) => s.key === "efficiency");

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: "year", width: 150, chartDataType: "category" },
    { field: "generated", chartDataType: "series", cellDataType: "number" },
    { field: "consumed", chartDataType: "series", cellDataType: "number" },
    { field: "surplus", chartDataType: "series", cellDataType: "number" },
    { field: "efficiency", chartDataType: "series", cellDataType: "number" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        axes: {
          number: {
            title: {
              enabled: true,
              formatter: (params) => {
                return isEfficiencySeries(params)
                  ? "Efficiency (%)"
                  : titleFormatter(params);
              },
            },
            label: {
              formatter: (params) => {
                return isEfficiencySeries(params)
                  ? `${params.value}%`
                  : siFormatter(params);
              },
            },
          },
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    setRowData(data);
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createRangeChart({
      cellRange: {
        rowStartIndex: 0,
        rowEndIndex: 4,
        columns: ["year", "generated", "consumed", "surplus", "efficiency"],
      },
      seriesChartTypes: [
        {
          colId: "generated",
          chartType: "groupedColumn",
          secondaryAxis: false,
        },
        { colId: "consumed", chartType: "groupedColumn", secondaryAxis: false },
        { colId: "surplus", chartType: "groupedColumn", secondaryAxis: false },
        { colId: "efficiency", chartType: "line", secondaryAxis: true },
      ],
      chartType: "columnLineCombo",
      chartContainer: document.querySelector("#myChart") as any,
      aggFunc: "sum",
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div id="wrapper">
          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              popupParent={popupParent}
              cellSelection={true}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
          <div id="myChart"></div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Label Formatting](https://www.ag-grid.com/examples/integrated-charts-customisation/label-formatting/reactFunctionalTs)

For more information on the `formatter` property for axes labels, see AG Charts Axis Labels [Label Text Formatting](https://www.ag-grid.com/charts/javascript/axes-labels/#label-text-formatting).

### Global Formatter

A single, top‑level `formatter` can be used to control the text for every label‑bearing element, e.g. axes, series labels, legend items, callouts, etc. The formatter will run for each element, unless that element defines its own `formatter`.

The callback receives the similar `params` object provided to element‑level formatters, providing access to properties such as `value`, `type`, and `elementId`. See the [AG Charts API Reference](https://charts.ag-grid.com/themes-api/#reference-AgChartTheme-overrides-common-formatter) for more information.

```jsx
const chartThemeOverrides = useMemo(() => { 
	return {
        common: {
            formatter: (params) => {
                if (params.type === 'number') {
                    return `£${params.value}`;
                    // prefix with `£` sign
                }
                const gridApi = params.context.api;
                // do something with the grid API
            }
        }
    };
}, []);

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

The example below shows a global formatter that prefixes all number values with a `£` symbol.

#### Global Label Formatter

```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,
  FormatterParams,
} from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ChartRef,
  ChartToolPanelsDef,
  ChartType,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

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

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

let chartRef: ChartRef;

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: "period",
      chartDataType: "category",
      headerName: "Financial Period",
      width: 150,
    },
    {
      field: "recurring",
      chartDataType: "series",
      headerName: "Recurring Revenue",
    },
    {
      field: "individual",
      chartDataType: "series",
      headerName: "Individual Sales",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartToolPanelsDef = useMemo<ChartToolPanelsDef>(() => {
    return {
      defaultToolPanel: "settings",
    };
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        formatter: (params: FormatterParams) => {
          if (params.type === "number") {
            return `£${params.value}`;
          }
        },
      },
    };
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    chartRef = params.api.createRangeChart({
      chartContainer: document.querySelector("#myChart") as HTMLElement,
      cellRange: {
        columns: ["period", "recurring", "individual"],
      },
      chartType: "groupedColumn",
    })!;
  }, []);

  const updateChart = useCallback(
    (chartType: ChartType) => {
      gridRef.current!.api.updateChart({
        type: "rangeChartUpdate",
        chartId: `${chartRef.chartId}`,
        chartType: chartType,
      });
    },
    [chartRef],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="wrapper">
          <div className="button-container">
            <button onClick={() => updateChart("groupedColumn")}>
              Grouped Column
            </button>
            <button onClick={() => updateChart("line")}>Line</button>
            <button onClick={() => updateChart("donut")}>Donut</button>
          </div>

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

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

[Live example: Global Label Formatter](https://www.ag-grid.com/examples/integrated-charts-customisation/global-label-formatter/reactFunctionalTs)

The order of formatting is as follows:

1. Element‑specific `label.formatter` (axis, series, legend, callout, etc.)
2. Global `formatter`
3. Default AG Charts formatting rules

### Accessing Grid Context in Formatters

The grid will pass the grid API and context into the `context` property of the formatter parameters.

Properties available on the `GridChartContext&lt;TData = any, TContext = any&gt;` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `api` | [`GridApi`](https://www.ag-grid.com/react-data-grid/grid-api/) |  |  | The grid api. |
| `context` | [`TContext`](https://www.ag-grid.com/react-data-grid/typescript-generics/#context-tcontext) |  |  | Application context as set on `gridOptions.context`. |

For formatters that are directly linked to row data, the row node will be passed in the `datum.node` property (note that `datum` may be undefined).

For formatters related to columns, the `key` property will usually contain the column ID. In some instances this will be in the `key` property of the corresponding series in the `boundSeries` property.

In the example below, the global formatter is used to access the `valueFormatter` in each of the columns:

- The x axis uses the **Financial Period** column value formatter.
- The y axis does not use a formatter as it belongs to multiple columns.
- The tooltip (when mousing over the series) uses the value formatters from each of the three columns.

#### Formatter Context

```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,
  FormatterParams,
} from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ChartRef,
  ChartToolPanelsDef,
  ChartType,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  FirstDataRenderedEvent,
  GridApi,
  GridChartContext,
  GridOptions,
  GridReadyEvent,
  IRowNode,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

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

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  ColumnApiModule,
];

let chartRef: ChartRef;

function formatValue(
  colId: string | undefined,
  node: IRowNode | undefined,
  chartContext: GridChartContext,
  value: any,
) {
  const column = colId ? chartContext.api.getColumn(colId) : null;
  if (column) {
    const colDef = column.getColDef();
    const valueFormatter = colDef.valueFormatter;
    if (typeof valueFormatter === "function") {
      const formattedValue = valueFormatter({
        ...chartContext,
        column,
        colDef,
        node: node ?? null,
        data: node?.data,
        value,
      });
      return formattedValue;
    }
  }
  return undefined;
}

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: "period",
      chartDataType: "category",
      headerName: "Financial Period",
      width: 150,
      valueFormatter: (params) => {
        const parts = params.value?.split(" ");
        return parts ? `${parts[1]} - ${parts[0]}` : "";
      },
    },
    {
      field: "recurring",
      chartDataType: "series",
      headerName: "Recurring Revenue",
      valueFormatter: (params) => {
        return `£${params.value}`;
      },
    },
    {
      field: "individual",
      chartDataType: "series",
      headerName: "Individual Sales",
      valueFormatter: (params) => {
        return `$${params.value}`;
      },
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartToolPanelsDef = useMemo<ChartToolPanelsDef>(() => {
    return {
      defaultToolPanel: "settings",
    };
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        formatter: (params: FormatterParams) => {
          const { type, key, datum, value, context, boundSeries } = params;
          if (type === "number") {
            return formatValue(
              key,
              datum?.node,
              context as GridChartContext,
              value,
            );
          }
          if (type === "category") {
            return formatValue(
              boundSeries?.[0]?.key,
              datum?.node,
              context as GridChartContext,
              value?.toString(),
            );
          }
          // fall back to default
          return undefined;
        },
      },
    };
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    chartRef = params.api.createRangeChart({
      chartContainer: document.querySelector("#myChart") as HTMLElement,
      cellRange: {
        columns: ["period", "recurring", "individual"],
      },
      chartType: "groupedColumn",
    })!;
  }, []);

  const updateChart = useCallback(
    (chartType: ChartType) => {
      gridRef.current!.api.updateChart({
        type: "rangeChartUpdate",
        chartId: `${chartRef.chartId}`,
        chartType: chartType,
      });
    },
    [chartRef],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="wrapper">
          <div className="button-container">
            <button onClick={() => updateChart("groupedColumn")}>
              Grouped Column
            </button>
            <button onClick={() => updateChart("line")}>Line</button>
            <button onClick={() => updateChart("donut")}>Donut</button>
          </div>

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

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

[Live example: Formatter Context](https://www.ag-grid.com/examples/integrated-charts-customisation/formatter-context/reactFunctionalTs)
