---
title: "Aggregation - Total Rows"
enterprise: true
framework: react
version: "36.1.0"
---

# Aggregation - Total Rows

This section shows how to include group and grand total rows in the grid.

## Enabling a Grand Total Row

A grand total row can be included in the grid by setting the `grandTotalRow` grid option to one of: `"top"`, `"bottom"`, `"pinnedTop"` or `"pinnedBottom"`.

Setting a value of `"top"` or `"bottom"` renders the grand total row as the first or last row in the grid, respectively. Setting a value of `"pinnedTop"` or `"pinnedBottom"` renders the grand total row pinned to the top or bottom of the grid, respectively.

> **Note**
>
> Grand total rows are also supported with the [Server-Side Row Model](https://www.ag-grid.com/react-data-grid/server-side-model-grouping/#grand-total-row), including on flat grids without grouping.

#### Enabling Grand Total Row

```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,
  PinnedRowModule,
  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, PinnedRowModule];

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: "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 {
      minWidth: 300,
    };
  }, []);

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

  const onChange = useCallback(() => {
    const grandTotalRow = document.querySelector<HTMLInputElement>(
      "#input-property-value",
    )!.value;
    if (
      grandTotalRow === "bottom" ||
      grandTotalRow === "top" ||
      grandTotalRow === "pinnedTop" ||
      grandTotalRow === "pinnedBottom"
    ) {
      gridRef.current!.api.setGridOption("grandTotalRow", grandTotalRow);
    } else {
      gridRef.current!.api.setGridOption("grandTotalRow", undefined);
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>grandTotalRow:</span>
              <select id="input-property-value" onChange={onChange}>
                <option value="bottom">"bottom"</option>
                <option value="top">"top"</option>
                <option value="pinnedBottom">"pinnedBottom"</option>
                <option value="pinnedTop">"pinnedTop"</option>
                <option value="undefined">undefined</option>
              </select>
            </label>
          </div>

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

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

[Live example: Enabling Grand Total Row](https://www.ag-grid.com/examples/aggregation-total-rows/enabling-grand-total/reactFunctionalTs)

The following configuration shows how grand total rows can be included at the bottom of the grid:

```jsx
const grandTotalRow = 'bottom';

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

## Enabling Group Total Rows

A total row can be included in every group when using [Row Grouping](https://www.ag-grid.com/react-data-grid/grouping/) or [Tree Data](https://www.ag-grid.com/react-data-grid/tree-data/) by setting the `groupTotalRow` grid option to either `"top"` or `"bottom"`. The provided value determines whether the total row will be included as the first or last row in the group.

#### Enabling Group Total Row

```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,
  UseGroupTotalRow,
  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", rowGroup: true, hide: true },
    { 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 {
      minWidth: 300,
    };
  }, []);

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

  const onChange = useCallback(() => {
    const groupTotalRow = document.querySelector<HTMLInputElement>(
      "#input-property-value",
    )!.value;
    if (groupTotalRow === "bottom" || groupTotalRow === "top") {
      gridRef.current!.api.setGridOption("groupTotalRow", groupTotalRow);
    } else {
      gridRef.current!.api.setGridOption("groupTotalRow", undefined);
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>groupTotalRow:</span>
              <select id="input-property-value" onChange={onChange}>
                <option value="bottom">"bottom"</option>
                <option value="top">"top"</option>
                <option value="undefined">undefined</option>
              </select>
            </label>
          </div>

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

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

[Live example: Enabling Group Total Row](https://www.ag-grid.com/examples/aggregation-total-rows/enabling-group-total/reactFunctionalTs)

The following configuration shows how group total rows can be included at the bottom of every group:

```jsx
// adds subtotals to the bottom of each row group
const groupTotalRow = 'bottom';

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

### Selectively Display Group Total Rows

Total rows can be applied to certain groups selectively by providing a callback to the `groupTotalRow` grid option. This callback should return `"top"`, `"bottom"` or `undefined` and will be called for each row group to determine whether the group should display a total row.

#### Selectively Enabling Group Footers

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

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

const modules = [RowApiModule, 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", rowGroup: true, hide: true },
    { 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 {
      minWidth: 300,
    };
  }, []);
  const groupTotalRow = useCallback((params: GetGroupIncludeTotalRowParams) => {
    const node = params.node;
    if (node && node.level === 1) return "bottom";
    if (node && node.key === "United States") return "bottom";
    return undefined;
  }, []);

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

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.forEachNode((node) => {
      if (node.key === "United States" || node.key === "Russia") {
        params.api.setRowNodeExpanded(node, true);
      }
    });
  }, []);

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

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

[Live example: Selectively Enabling Group Footers](https://www.ag-grid.com/examples/aggregation-total-rows/enabling-group-total-selectively/reactFunctionalTs)

The example above demonstrates the following configuration to display total rows for the `"United States"` group, and the rows grouped by the `"year"` field:

```jsx
const groupTotalRow = (params) => {
    const node = params.node;
    if (node && node.level === 1) return 'bottom';
    if (node && node.key === 'United States') return 'bottom';
    return undefined;
};

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

### Keeping Group Row Values

When a total row is visible, the group row values are hidden. This behaviour can be prevented by setting the `groupSuppressBlankHeader` grid option to `true`.

#### Suppress Blank 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 "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  UseGroupTotalRow,
  enableDevValidations,
} from "ag-grid-community";
import { RowGroupingModule } from "ag-grid-enterprise";
import { useFetchJson } from "./useFetchJson";

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(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", rowGroup: true, hide: true },
    { 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 {
      minWidth: 300,
    };
  }, []);

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

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

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

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              groupTotalRow={"bottom"}
              groupDefaultExpanded={1}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Suppress Blank Groups](https://www.ag-grid.com/examples/aggregation-total-rows/suppress-blank-groups/reactFunctionalTs)

The configuration below demonstrates the configuration for preventing the hiding of group row values:

```jsx
const groupSuppressBlankHeader = true;

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

## Group Column Cell Values

When using [Row Grouping](https://www.ag-grid.com/react-data-grid/grouping-display-types/) or [Tree Data](https://www.ag-grid.com/react-data-grid/tree-data-group-column/) with group columns, the group cell will display `"Total"` by default in the footer rows.

The default `agGroupCellRenderer.cellRendererParams` can be provided with a `totalValueGetter` to configure the value displayed in this cell.

#### Customising Footer Values

```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,
  UseGroupTotalRow,
  enableDevValidations,
} from "ag-grid-community";
import { RowGroupingModule } from "ag-grid-enterprise";
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", rowGroup: true, hide: true },
    { 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 {
      minWidth: 300,
      cellRendererParams: {
        totalValueGetter: (params: any) => {
          const isRootLevel = params.node.level === -1;
          if (isRootLevel) {
            return "Grand Total";
          }
          return `Sub Total (${params.value})`;
        },
      },
    };
  }, []);

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

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            groupTotalRow={"bottom"}
            grandTotalRow={"bottom"}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Customising Footer Values](https://www.ag-grid.com/examples/aggregation-total-rows/customising-footer-values/reactFunctionalTs)

The example above demonstrates using the following configuration to display custom group column values for grand total and group total rows:

```jsx
const autoGroupColumnDef = useMemo(() => { 
	return {
        cellRendererParams: {
            totalValueGetter: params =>  {
                const isRootLevel = params.node.level === -1;
                if (isRootLevel) {
                    return 'Grand Total';
                }
                return `Sub Total (${params.value})`;
            },
        }
    };
}, []);

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

> **Note**
>
> When exporting, copying custom footers, or using Find with custom group cell values, the custom content must also be added using [processRowGroupCallback](https://www.ag-grid.com/react-data-grid/excel-export-customising-content/) for export, [processCellForClipboard](https://www.ag-grid.com/react-data-grid/clipboard/#processing-individual-cells) for copying to clipboard, or [getFindText](https://www.ag-grid.com/react-data-grid/find/#using-find-with-cell-components) for Find.

## Suppress Sticky Rows

All total rows stick to the top or bottom of the viewport when scrolling. This behaviour can be configured by using the `suppressStickyTotalRow` grid option.

#### Suppress Sticky Total Rows

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

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

const modules = [ClientSideRowModelModule, RowGroupingModule];

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(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", rowGroup: true, hide: true },
    { 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 {
      minWidth: 300,
    };
  }, []);

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

  const onChange = useCallback(() => {
    const suppressStickyTotalRow = document.querySelector<HTMLInputElement>(
      "#input-property-value",
    )!.value;
    if (
      suppressStickyTotalRow === "grand" ||
      suppressStickyTotalRow === "group"
    ) {
      gridRef.current!.api.setGridOption(
        "suppressStickyTotalRow",
        suppressStickyTotalRow,
      );
    } else if (suppressStickyTotalRow === "true") {
      gridRef.current!.api.setGridOption("suppressStickyTotalRow", true);
    } else {
      gridRef.current!.api.setGridOption("suppressStickyTotalRow", false);
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              <span>suppressStickyTotalRow:</span>
              <select id="input-property-value" onChange={onChange}>
                <option value="false">false</option>
                <option value="true">true</option>
                <option value="grand">"grand"</option>
                <option value="group">"group"</option>
              </select>
            </label>
          </div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              groupDefaultExpanded={-1}
              groupTotalRow={"bottom"}
              grandTotalRow={"bottom"}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Suppress Sticky Total Rows](https://www.ag-grid.com/examples/aggregation-total-rows/suppress-sticky-total-rows/reactFunctionalTs)

The following configuration demonstrates how to suppress sticky behaviour for both grand and group total rows:

```jsx
const suppressStickyTotalRow = true;

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