---
title: "Pivot Column Groups"
enterprise: true
framework: react
version: "36.1.0"
---

# Pivot Column Groups

The grid generates pivot column groups representing each unique pivoted value.

#### Column Group Summary Example

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true },
    { field: "sport", pivot: true },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div
          style={{ display: "flex", flexDirection: "column", height: "100%" }}
        >
          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              pivotMode={true}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Column Group Summary Example](https://www.ag-grid.com/examples/pivoting-column-groups/column-group-summary/reactFunctionalTs/)

## Customising Group Definitions

Pivot Result Column Group definitions can be configured using the `processPivotResultColGroupDef` grid option.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `processPivotResultColGroupDef` | `ProcessPivotResultColGroupDef` |  |  | Callback for the mutation of the generated pivot result column group definitions Module: [`PivotModule`](https://www.ag-grid.com/react-data-grid/modules/). |

In the example below, the `processPivotResultColGroupDef` callback is used to apply a class to the group header cells, which is subsequently used to style them with a golden background.

#### Column Group Definitions Example

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  ProcessPivotResultColGroupDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true },
    { field: "sport", pivot: true },
    { field: "gold", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);
  const processPivotResultColGroupDef = useCallback((colDef) => {
    colDef.headerClass = "pivot-gold";
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div
          style={{ display: "flex", flexDirection: "column", height: "100%" }}
        >
          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              pivotMode={true}
              processPivotResultColGroupDef={processPivotResultColGroupDef}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Column Group Definitions Example](https://www.ag-grid.com/examples/pivoting-column-groups/column-group-definitions-example/reactFunctionalTs/)

This demonstrates the following configuration for applying a class to the group header cells:

```jsx
const pivotMode = true;
const processPivotResultColGroupDef = useCallback((colDef) => {
    colDef.headerClass = 'pivot-gold'; // the params are mutated directly, not returned
}, []);

<AgGridReact
    pivotMode={pivotMode}
    processPivotResultColGroupDef={processPivotResultColGroupDef}
/>
```

## Ordering Groups

The pivot result groups are initially displayed in alphabetical order. You can change this default order by providing a `pivotComparator` function to the pivoted column's definition.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `pivotComparator` | `PivotComparatorFunc` |  |  | Comparator to use when ordering the pivot result groups generated when this column is used to pivot on. The values will always be strings, as the pivot service uses strings as keys for the pivot groups. Defines the ascending order: `pivotSort: 'desc'` reverses it, and `pivotSort: null` bypasses it to keep the order the groups were generated in. Groups are ordered by header name when this is not supplied. Module: [`PivotModule`](https://www.ag-grid.com/react-data-grid/modules/). [Initial](https://www.ag-grid.com/react-data-grid/grid-interface/#initial-grid-options). |

In the example below, note that a `pivotComparator` has been supplied to the `sport` column, and the pivot result groups are instead sorted in reversed alphabetical order.

#### Ordering Pivot Groups

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { PivotModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [ClientSideRowModelModule, PivotModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true },
    {
      field: "sport",
      pivot: true,
      pivotComparator: (a: string, b: string) => b.localeCompare(a),
    },
    { field: "gold", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            pivotMode={true}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Ordering Pivot Groups](https://www.ag-grid.com/examples/pivoting-column-groups/order-pivot-groups/reactFunctionalTs/)

This demonstrates the following configuration for modifying the resulting order of groups:

```jsx
const [columnDefs, setColumnDefs] = useState([
    // ...other column definitions
    {
        field: 'sport',
        pivot: true,
        pivotComparator: (a, b) => b.localeCompare(a),
    },
]);
const pivotMode = true;

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

> **Note**
>
> If the `pivotComparator` returns 0, the order of the groups is then further determined by the order in which they appear in the data.
>
> This means that writing a `pivotComparator` function that always returns 0 will result in the groups being ordered by the order in which they appear in the data.

### Changing Data, Filters, and Configurations

When changing data, filters, or configurations such as `pivotRowTotals` the generated column groups and their order is impacted. The grid will add new columns and column groups at the end of their parent groups. This is to maintain any changes the user may have made to their column order.

This behaviour can be toggled to instead reset the column order when the columns are generated by setting the `enableStrictPivotColumnOrder` grid option to `true`.

The example below demonstrates a changing data set while in pivot mode. Note that when `enableStrictPivotColumnOrder` is set to `false`, new columns are appended. When set to `true` all columns are re-sorted according to the `pivotComparator` (or alphanumerically if omitted).

#### Strict Column Order

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { PivotModule } from "ag-grid-enterprise";
import { getData } from "./data";

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

const modules = [ClientSideRowModelModule, PivotModule];

let count = 0;

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: "pivotValue", pivot: true },
    { field: "agg", aggFunc: "sum", rowGroup: true },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      width: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 100,
    };
  }, []);
  const getRowId = useCallback((p) => String(p.data.pivotValue), []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    setInterval(() => {
      count += 1;
      const rowData = getData();
      setRowData(rowData.slice(0, (count % rowData.length) + 1));
    }, 1000);
  }, []);

  const toggleOption = useCallback(() => {
    const isChecked = document.querySelector<HTMLInputElement>(
      "#enableStrictPivotColumnOrder",
    )!.checked;
    gridRef.current!.api.setGridOption(
      "enableStrictPivotColumnOrder",
      isChecked,
    );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>enableStrictPivotColumnOrder:</span>
              <input
                id="enableStrictPivotColumnOrder"
                type="checkbox"
                onChange={toggleOption}
              />
            </label>
          </div>

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

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

[Live example: Strict Column Order](https://www.ag-grid.com/examples/pivoting-column-groups/strict-column-order/reactFunctionalTs/)

This demonstrates the following configuration for changing the behaviour for new column groups:

```jsx
const enableStrictPivotColumnOrder = true;

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

## Sorting Pivot Columns

End users can sort the pivot columns by clicking a pivot column's pill in the pivot panel or the Column Tool Panel, the same way row group columns are sorted from their pills.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `pivotSort` | `SortDirection` |  | `'asc'` | Sort direction applied to this column's pivot result columns when this column is used to pivot on. Independent of `sort` - pivot sorting does not flow to or from the column's own sort. Defaults to `'asc'` for the pivot result columns the grid generates. When the pivot result columns are supplied by the application via `setPivotResultColumns`, it defaults to `null` so the supplied order is kept until a sort is applied. Module: [`PivotModule`](https://www.ag-grid.com/react-data-grid/modules/). |

`pivotSort` is independent of `sort`: it controls the order of a pivoted column's result columns only, and neither direction flows to or from the column's own sort. Pivot columns the grid generates are sorted ascending by default, while pivot result columns supplied through [`setPivotResultColumns`](https://www.ag-grid.com/react-data-grid/server-side-model-pivoting/#creating-pivot-result-columns-advanced) default to no sort so their supplied order is kept. Clicking a pill cycles through ascending, descending and no sort, where no sort keeps the order the columns were generated or supplied in. When a `pivotComparator` is supplied, ascending uses that comparator's order and descending reverses it.

#### Sorting Pivot Columns

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  PivotModule,
  RowGroupingPanelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "country",
      rowGroup: true,
      enableRowGroup: true,
      enablePivot: true,
    },
    { field: "sport", enableRowGroup: true, enablePivot: true },
    { field: "year", pivot: true, enableRowGroup: true, enablePivot: true },
    { field: "age", enableValue: true },
    { field: "gold", aggFunc: "sum", enableValue: true },
    { field: "silver", enableValue: true },
    { field: "bronze", enableValue: true },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);
  const sideBar = useMemo<
    SideBarDef | string | string[] | boolean | null
  >(() => {
    return {
      toolPanels: ["columns"],
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            pivotMode={true}
            sideBar={sideBar}
            rowGroupPanelShow={"always"}
            pivotPanelShow={"always"}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Sorting Pivot Columns](https://www.ag-grid.com/examples/pivoting-column-groups/sort-pivot-columns/reactFunctionalTs/)

The direction can also be set through the API using `applyColumnState`:

```jsx
gridApi.applyColumnState({
    state: [{ colId: 'year', pivotSort: 'desc' }],
});
```

Sorting reorders the pivot column groups while preserving any column width and within-group ordering changes the user has made.

Set the `pivotPanelSuppressSort` grid option to `true` to disable this interaction. Pills for columns with `sortable: false` are not interactive, though `pivotSort` can still be set on them via `applyColumnState`.

## Pivoting by Dates and Times

When pivoting by date/time values, the grid can optionally generate pivot group columns based on components of the date/time.

To enable this for a particular column, use the `groupHierarchy` property of the [Column Definition](https://www.ag-grid.com/react-data-grid/column-properties/#reference-grouping-groupHierarchy).

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `groupHierarchy` | [`(GroupHierarchyParts \| string \| ColDef)[]`](https://www.ag-grid.com/react-data-grid/column-properties/) |  |  | Specify a grouping hierarchy for this column. This generates one or more virtual columns to group or pivot by when this column is grouped or pivoted. This can be used to group/pivot by values derived from a source column. The grid provides hierarchy types related to date components. Users can provide their own hierarchy types by specifying a `ColDef`, or referring to the name of a hierarchy type defined in `groupHierarchyConfig`. Modules (any of): [`RowGroupingModule`](https://www.ag-grid.com/react-data-grid/modules/), [`PivotModule`](https://www.ag-grid.com/react-data-grid/modules/). |

```jsx
const [columnDefs, setColumnDefs] = useState([
    {
        field: 'date',
        pivot: true,
        groupHierarchy: ['year', 'month']
    },
    // ...other column definitions
]);

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

This snippet is illustrated in the example below.

#### Pivoting by Dates and Times

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGroupColumnDef,
  CellStyleModule,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

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

const modules = [
  CellStyleModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "date",
      pivot: true,
      groupHierarchy: ["year", "formattedMonth"],
    },
    { field: "country", rowGroup: true },
    { field: "sport" },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: IOlympicData[]) =>
        setRowData(
          data.map((d) => ({
            ...d,
            date: d.date?.split("/").reverse().join("-"),
          })),
        ),
      );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div
          style={{ display: "flex", flexDirection: "column", height: "100%" }}
        >
          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              pivotMode={true}
              onGridReady={onGridReady}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Pivoting by Dates and Times](https://www.ag-grid.com/examples/pivoting-column-groups/pivoting-date-time/reactFunctionalTs/)

> **Note**
>
> Date values must be formatted as ISO-8601 dates in order to be correctly parsed into their components.

## Filtering Pivoted Columns

When pivoting is active, filters can be applied to columns defined within the column definitions by using the [Filters Tool Panel](https://www.ag-grid.com/react-data-grid/tool-panel-filters/) and the [Filter API](https://www.ag-grid.com/react-data-grid/grid-api/#reference-filter).

In the example below, applying a filter to the `Sport` column (which has been pivoted) impacts the generated pivot column groups, instead of the grid rows or cell values.

#### Filtering Pivoted Columns

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  PivotModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  NumberFilterModule,
  ClientSideRowModelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
  SetFilterModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true, filter: true },
    { field: "sport", pivot: true, filter: true },
    { field: "gold", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 150,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    const filtersToolPanel = params.api.getToolPanelInstance("filters");
    if (filtersToolPanel) {
      // expands 'year' and 'sport' filters in the Filters Tool Panel
      filtersToolPanel.expandFilters(["sport"]);
    }
  }, []);
  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            pivotMode={true}
            sideBar={"filters"}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Filtering Pivoted Columns](https://www.ag-grid.com/examples/pivoting-column-groups/filter-pivoted-columns/reactFunctionalTs/)

> **Note**
>
> When filtering a pivoted column, the resulting pivot result column group is removed from the grid. If the filter is subsequently removed, the column group will be re-added to the end of grid.
>
> To configure this behaviour, refer to the section for [Changing Data, Filters, and Configurations](https://www.ag-grid.com/react-data-grid/pivoting-column-groups/#changing-data-filters-and-configurations).

## Expanded by Default

Pivot Column Groups can be configured to expand by default, down to a given depth. This depth can be configured using the `pivotDefaultExpanded` grid option.

The example below demonstrates `pivotDefaultExpanded` being used to expand the first pivot group level by default. Providing `-1` will expand all pivot group levels by default.

#### Open Pivot Group By Default

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnGroup,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  PivotModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true, enableRowGroup: true },
    { field: "athlete" },
    { field: "sport", pivot: true, enablePivot: true },
    { field: "year", pivot: true, enablePivot: true },
    { field: "date", pivot: true, enablePivot: true },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            pivotMode={true}
            pivotDefaultExpanded={1}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Open Pivot Group By Default](https://www.ag-grid.com/examples/pivoting-column-groups/open-pivot-group-by-default/reactFunctionalTs/)

The example above demonstrates the following configuration for expanding pivot groups by default:

```jsx
const pivotDefaultExpanded = 1;

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

## Prevent Expanding Groups

When using multiple pivot columns, groups become expandable by default. To prevent this and instead always show all columns, set the grid option `suppressExpandablePivotGroups=true`.

#### Fixed Pivot Column Groups

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  PivotModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true, enableRowGroup: true },
    { field: "athlete" },
    { field: "sport", pivot: true, enablePivot: true },
    { field: "year", pivot: true, enablePivot: true },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            pivotMode={true}
            suppressExpandablePivotGroups={true}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Fixed Pivot Column Groups](https://www.ag-grid.com/examples/pivoting-column-groups/fixed-pivot-column-groups/reactFunctionalTs/)

The example above demonstrates the following configuration:

```jsx
const pivotMode = true;
const suppressExpandablePivotGroups = true;

<AgGridReact
    pivotMode={pivotMode}
    suppressExpandablePivotGroups={suppressExpandablePivotGroups}
/>
```

## Hide Group with Single Value Column

When pivoting with only one aggregated column, you can simplify the grid column header layout by omitting pivot column groups with only one child column. Enabling the grid option `removePivotHeaderRowWhenSingleValueColumn=true`, when set to `true` will instead skip the group and use the pivot keys to label the pivot result column instead.

#### Hiding Repeated Column Labels

```tsx
'use client';
import { useFetchJson } from './useFetchJson';
import React, {
  StrictMode,
  useCallback,
  useMemo,
  useRef,
  useState,
} from "react";
import { createRoot } from "react-dom/client";

import type { ColDef } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  PivotModule,
} from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import "./styles.css";

// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,

  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
];

interface IOlympicData {
  athlete: string;
  age: number;
  country: string;
  year: number;
  date: string;
  sport: string;
  gold: number;
  silver: number;
  bronze: number;
  total: number;
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IOlympicData>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroup: true },
    { field: "sport", pivot: true },
    { field: "gold", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
    };
  }, []);
  const autoGroupColumnDef = useMemo<ColDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  const togglePivotHeader = useCallback(() => {
    const checkbox = document.querySelector<HTMLInputElement>(
      "#removePivotHeaderRowWhenSingleValueColumn",
    )!;
    gridRef.current!.api.setGridOption(
      "removePivotHeaderRowWhenSingleValueColumn",
      checkbox.checked,
    );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>removePivotHeaderRowWhenSingleValueColumn:</span>
              <input
                type="checkbox"
                id="removePivotHeaderRowWhenSingleValueColumn"
                onChange={togglePivotHeader}
                defaultChecked
              />
            </label>
          </div>

          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              ref={gridRef}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              pivotMode={true}
              removePivotHeaderRowWhenSingleValueColumn={true}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Hiding Repeated Column Labels](https://www.ag-grid.com/examples/pivoting-column-groups/hidden-single-value-column-header/reactFunctionalTs/)

The example above demonstrates the following configuration:

```jsx
const [columnDefs, setColumnDefs] = useState([
    { field: 'country', rowGroup: true },
    { field: 'sport', pivot: true },
    { field: 'gold', aggFunc: 'sum' },
]);
const pivotMode = true;
const removePivotHeaderRowWhenSingleValueColumn = true;

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