---
title: "Row Grouping - Grouping Data"
enterprise: true
framework: react
version: "36.1.0"
---

# Row Grouping - Grouping Data

Enable grouping on a column to group rows by equivalent values.

## Enabling Row Grouping

Row Grouping is enabled by setting `rowGroup` to `true` on one or more [Column Definition](https://www.ag-grid.com/react-data-grid/column-definitions/). Parent rows are then introduced for each unique value in that column, containing the rows with that value.

#### Basic Grouping

```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 { RowGroupingModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

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, hide: true },
    { field: "year" },
    { field: "athlete" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  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}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Basic Grouping](https://www.ag-grid.com/examples/grouping-data/basic-grouping/reactFunctionalTs)

The example above uses the following configuration to group rows by their `country` values:

```jsx
const [columnDefs, setColumnDefs] = useState([
    { field: 'country', rowGroup: true },
    // ...other column definitions
]);

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

## Grouping by Multiple Columns

When grouping on multiple columns using `rowGroup`, the order of columns within the column definitions is used to determine which column to group by first. This can be overridden with a custom order by providing the `rowGroupIndex` property in each grouped columns definition.

#### Grouping by Multiple 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,
  enableDevValidations,
} from "ag-grid-community";
import { RowGroupingModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

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

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "country", rowGroupIndex: 1, hide: true },
    { field: "year", rowGroupIndex: 0, hide: true },
    { field: "athlete" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  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}
            groupDefaultExpanded={1}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Grouping by Multiple Columns](https://www.ag-grid.com/examples/grouping-data/row-group-index/reactFunctionalTs)

The example above demonstrates the following configuration for grouping rows by `year` first, and `country` second:

```jsx
const [columnDefs, setColumnDefs] = useState([
    { field: 'country', rowGroupIndex: 1 },
    { field: 'year', rowGroupIndex: 0 },
    // ...other column definitions
]);

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

## Grouping on Object Data

When grouping on object data, the grid needs a way to compare items to determine if they are equivalent. Setting a `keyCreator` on the grouped column definition provides the grid with string keys it can compare.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `keyCreator` | `KeyCreatorFunc` |  |  | Function to return a string key for a value. This string is used for grouping, Set filtering, and searching within cell editor dropdowns. When filtering and searching the string is exposed to the user, so make sure to return a human-readable value. |

The following example uses a custom set of rows, each containing an `athlete` field that maps to objects with `id` and `name` properties.

#### Grouping by Object Data

```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 { RowGroupingModule } from "ag-grid-enterprise";
import { getData } from "./data";

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "athlete",
      rowGroup: true,
      hide: true,
      keyCreator: (params) => params.value.id,
      valueFormatter: (params) => params.value.name,
    },
    { field: "country" },
    { field: "year" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

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

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

[Live example: Grouping by Object Data](https://www.ag-grid.com/examples/grouping-data/grouping-object-data/reactFunctionalTs)

This demonstrates the following configuration for grouping rows by the `athlete` objects by their `id` property:

```jsx
const [columnDefs, setColumnDefs] = useState([
    {
        field: 'athlete',
        rowGroup: true,
        keyCreator: (params) => params.value.id,
        valueFormatter: (params) => params.value.name,
    },
    // ...other column definitions
]);

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

## Grouping by Dates and Times

When grouping by date/time values, the grid can optionally group by components of the date/time.

To enable grouping by parts of the date 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',
        rowGroup: true,
        groupHierarchy: ['year', 'month']
    },
    // ...other column definitions
]);

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

This snippet is illustrated in the example below.

#### Grouping 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 "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingModule,
  RowGroupingPanelModule,
  SideBarModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

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

const modules = [
  ClientSideRowModelModule,
  RowGroupingModule,
  SideBarModule,
  ColumnsToolPanelModule,
  RowGroupingPanelModule,
  PivotModule,
];

const COL_DEFS: ColDef<IOlympicData>[] = [
  {
    field: "date",
    rowGroup: true,
    enableRowGroup: true,
    enablePivot: true,
    groupHierarchy: ["year", "month"],
    minWidth: 120,
  },
  { field: "country" },
  { field: "sport" },
  { field: "total", aggFunc: "sum" },
];

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IOlympicData>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>(COL_DEFS);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 225,
    };
  }, []);

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

  const onChangeFormattedMonth = useCallback((event: any) => {
    const month = event.target.checked ? "formattedMonth" : "month";
    COL_DEFS[0].groupHierarchy![1] = month;
    gridRef.current!.api.setGridOption("columnDefs", COL_DEFS);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <label style={{ marginBottom: "1rem" }}>
            <input
              id="formatted-month-checkbox"
              type="checkbox"
              onChange={() => onChangeFormattedMonth(event)}
            />
            <span>Use formatted month</span>
          </label>

          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              sideBar={"columns"}
              rowGroupPanelShow={"always"}
              onGridReady={onGridReady}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Grouping by Dates and Times](https://www.ag-grid.com/examples/grouping-data/grouping-date-time/reactFunctionalTs)

> **Note**
>
> By default, the grid requires datetime values to be formatted using the ISO-8601 format in order to be correctly parsed into their components.
>
> To use other date formats, provide a custom [Cell Data Type Definition](https://www.ag-grid.com/react-data-grid/cell-data-types/#providing-custom-cell-data-types) for the `dateString` and/or `dateTimeString` data types.

## Defining Custom Grouping Hierarchies

When using `groupHierarchy` as demonstrated in [Grouping by Dates and Times](https://www.ag-grid.com/react-data-grid/grouping-data/#grouping-by-dates-and-times), the grid provides built-in support for several components of a date/time value.

Users may instead provide definitions of their own components via the `groupHierarchyConfig` grid option. These definitions may then be used in the `groupHierarchy` property of a column definition.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `groupHierarchyConfig` | `GroupHierarchyConfig` |  |  | Custom group hierarchy components can be defined here for later use in `colDef.groupHierarchy` Module: [`RowGroupingModule`](https://www.ag-grid.com/react-data-grid/modules/). |

The following example illustrates this by defining a custom grouping hierarchy component that allows grouping by the week number:

#### Grouping 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,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  GroupHierarchyConfig,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingModule,
  RowGroupingPanelModule,
  SideBarModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

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

const modules = [
  ClientSideRowModelModule,
  RowGroupingModule,
  SideBarModule,
  ColumnsToolPanelModule,
  RowGroupingPanelModule,
  ColumnApiModule,
  PivotModule,
];

const getDate: (value: any) => Date | null = (value: any) => {
  if (value instanceof Date) {
    return value;
  }
  if (typeof value === "string") {
    const [year, month, day] = value.split("-");
    const d = new Date();
    d.setFullYear(parseInt(year, 10), parseInt(month, 10), parseInt(day, 10));
    d.setHours(0, 0, 0, 0);
    return d;
  }
  return null;
};

const getWeekNumber: (date: Date) => number = (date: Date) => {
  const d = new Date(date.getTime());
  d.setHours(0, 0, 0, 0);
  d.setDate(d.getDate() + 3 - ((date.getDay() + 6) % 7));
  const week1 = new Date(d.getFullYear(), 0, 4);
  return (
    1 +
    Math.round(
      ((d.getTime() - week1.getTime()) / 86400000 -
        3 +
        ((week1.getDay() + 6) % 7)) /
        7,
    )
  );
};

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",
      rowGroup: true,
      enableRowGroup: true,
      enablePivot: true,
      groupHierarchy: ["year", "week"],
      minWidth: 120,
    },
    { field: "country" },
    { field: "sport" },
    { field: "total", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 225,
    };
  }, []);
  const groupHierarchyConfig = useMemo<GroupHierarchyConfig>(() => {
    return {
      week: {
        headerValueGetter: (params) => {
          const sourceCol = params.api
            .getColumns()
            ?.find((col) => col.getColDef().field === "date");
          if (!sourceCol) return "";
          const name = params.api.getDisplayNameForColumn(
            sourceCol,
            params.location,
          );
          return `${name} (Week)`;
        },
        valueGetter: (params) => {
          const sourceCol = params.api
            .getColumns()
            ?.find((col) => col.getColDef().field === "date");
          const field = sourceCol?.getColDef().field;
          if (!field) return;
          const value = params.getValue(field);
          const date = getDate(value);
          if (!date) return;
          return getWeekNumber(date).toString();
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/small-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={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            sideBar={"columns"}
            rowGroupPanelShow={"always"}
            groupHierarchyConfig={groupHierarchyConfig}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Grouping by Dates and Times](https://www.ag-grid.com/examples/grouping-data/grouping-custom-date-time/reactFunctionalTs)

## Grouping on Null and Undefined Data

When grouping `null`, `undefined` or `""` (empty string) values the grid will group these together under the heading `(Blanks)` as the final group.

By setting the `groupAllowUnbalanced` property to `true`, the grid will instead display these rows without a group.

#### Grouping by Null and Undefined Data

```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,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { RowGroupingModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

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, hide: true },
    { field: "year" },
    { field: "athlete" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

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

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

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

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

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

[Live example: Grouping by Null and Undefined Data](https://www.ag-grid.com/examples/grouping-data/grouping-null-undefined/reactFunctionalTs)

To enable unbalanced grouping, the following configuration is used:

```jsx
const groupAllowUnbalanced = true;

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

## Hiding Parents of Individual Rows

Groups with only a single child can be hidden from the grid by setting the `groupHideParentOfSingleChild` grid option to `true`. To remove only groups with a single leaf child, set this option to `"leafGroupsOnly"` instead.

Filtering does not impact which groups get removed. Only groups containing a single child prior to filtering being applied are removed.

#### Removing Single Children

```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,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  SetFilterModule,
];

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[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country", rowGroup: true },
    { field: "city", rowGroup: true },
    { field: "year" },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 150,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      headerName: "Group",
      field: "athlete",
      minWidth: 220,
      cellRenderer: "agGroupCellRenderer",
    };
  }, []);

  const onOptionChange = useCallback(() => {
    const key = (
      document.querySelector("#input-display-type") as HTMLSelectElement
    ).value;
    if (key === "true" || key === "false") {
      gridRef.current!.api.setGridOption(
        "groupHideParentOfSingleChild",
        key === "true",
      );
    } else {
      gridRef.current!.api.setGridOption(
        "groupHideParentOfSingleChild",
        "leafGroupsOnly",
      );
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>groupHideParentOfSingleChild:</span>
              <select id="input-display-type" onChange={onOptionChange}>
                <option value="false">false</option>
                <option value="true">true</option>
                <option value="leafGroupsOnly">"leafGroupsOnly"</option>
              </select>
            </label>
          </div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              groupDefaultExpanded={-1}
              suppressAggFuncInHeader={true}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Removing Single Children](https://www.ag-grid.com/examples/grouping-data/remove-single-children/reactFunctionalTs)

The following is an example of the configuration used to hide all parents of a single row:

```jsx
const groupHideParentOfSingleChild = true;

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

> **Note**
>
> The properties `groupHideParentOfSingleChild` and `groupHideOpenParents` are mutually exclusive.
