---
title: Aggregate Data within a Form
product: Form Library
description: The Dynamic Matrix question enables you to perform various calculations on user input and consolidate this data into separate rows and/or columns based on the selected data aggregation type. For instance, if you want to calculate the total cost of items within a form, you'll need to set the aggregation type to 'Sum'. View this demo to learn more and access ready-to-use code examples for JavaScript.
framework: React
source: https://surveyjs.io/form-library/examples/aggregate-data-within-form/reactjs
index: https://surveyjs.io/form-library/examples/overview.md
---

# Aggregate Data within a Form (React)

Dynamic Matrix supports different data aggregation methods that you can use to combine or summarize data across multiple matrix rows or columns based on provided answers. For instance, in a Dynamic Matrix where users input numerical values, aggregation might involve calculating totals, averages, counts, or other statistical operations across rows or columns. This example illustrates the dynamic generation of Totals for rows and columns based on selected phone models and their quantities.

## Calculate Row Totals

A row total aggregates values in a particular matrix row. To calculate and display row totals, create a column with the `cellType` property set to `"expression"`. Create an expression to calculate row totals. Within the expression, you can access individual row cells using the `row` prefix as follows: `{row.columnName}`. For a code example, refer to the "Total" column configuration in the `survey.json` file.

## Calculate Column Totals

A column total aggregates values in an individual matrix column. Use the following column properties to configure column totals:

- `totalType`: `"sum"` | `"count"` | `"min"` | `"max"` | `"avg"`        
An aggregation method.

- `totalDisplayStyle`: `"decimal"` | `"currency"` | `"percent"`         
A format for calculated total values.

- `totalFormat`: `string`        
A string pattern used to display column totals. To reference a total value within this pattern, use the `{0}` placeholder.

This demo calculates column totals for the "Phone model", "Quantity", and "Total" columns. You can find their configurations in the `survey.json` file.

To access the total value of an individual column, use the `total` suffix as follows: `{matrixName-columnName.total}`. In the current demo, this suffix is used by the "VAT" and "Total" questions. Refer to the `survey.json` file for a code example.

## Files

### `public/index.html`

```html
<div id="surveyElement" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; min-height: 100%; height:100%"></div>
```

### `src/SurveyComponent.jsx`

```js
import React from "react";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";
import "survey-core/survey-core.min.css";
import "./index.css";
import { json } from "./json";
import { Serializer, registerFunction } from "survey-core";

// Add the `price` property to choice options
Serializer.addProperty("itemvalue", "price:number");

// A custom function that returns a selected item's price
const getItemPrice = function (params) {
    // `this.row` is available only within matrix cells
    const question = this.row ? this.row.getQuestionByColumnName(params[0]) : null;
    if (!question) return 0;
    const selectedItem = question.selectedItem;
    // Return 0 if a user haven't selected an item yet
    return selectedItem ? selectedItem.price : 0;
};
registerFunction({ name: "getItemPrice", func: getItemPrice });

function SurveyComponent() {
    const survey = new Model(json);
    survey.onComplete.add((sender, options) => {
        console.log(JSON.stringify(sender.data, null, 3));
    });
    survey.data = {
        "vatPercentage": 20,
        "orders": [{
            "id": 1,
            "phone_model": "iPhone15ProMax-1024",
            "quantity": 1,
        }, {
            "id": 2,
            "phone_model": "iPhone15-256",
            "quantity": 2,
        }, {
            "id": 3,
            "phone_model": "iPhone14Pro-512",
            "quantity": 2,
        }]
    };
    return (<Survey model={survey} />);
}

export default SurveyComponent;
```

### `src/index.css`

```css
/* You can add your custom CSS here. */
```

### `src/index.js`

```js
import React from "react";
import { createRoot } from "react-dom/client";
import SurveyComponent from "./SurveyComponent";

const root = createRoot(document.getElementById("surveyElement"));
root.render(<SurveyComponent />);
```

### `src/json.js`

```js
export const json = {
  "elements": [
    {
      "type": "matrixdynamic",
      "name": "orders",
      "minRowCount": 1,
      "titleLocation": "hidden",
      "addRowText": "Add new item",
      "columns": [
        {
          "name": "id",
          "title": "Id",
          "cellType": "expression",
          "expression": "{rowIndex}",
          "visible": false
        },
        {
          "name": "phone_model",
          "title": "Phone model",
          "isRequired": true,
          "cellType":  "dropdown",
          "choices": [
            { "text": "iPhone 15 Pro Max, 256GB", "value": "iPhone15ProMax-256", "price": 1199 },
            { "text": "iPhone 15 Pro Max, 512GB", "value": "iPhone15ProMax-512", "price": 1399 },
            { "text": "iPhone 15 Pro Max, 1TB", "value": "iPhone15ProMax-1024", "price": 1599 },
            { "text": "iPhone 15 Pro, 128GB", "value": "iPhone15Pro-128", "price": 999 },
            { "text": "iPhone 15 Pro, 256GB", "value": "iPhone15Pro-256", "price": 1099 },
            { "text": "iPhone 15 Pro, 512GB", "value": "iPhone15Pro-512", "price": 1299 },
            { "text": "iPhone 15 Pro, 1TB", "value": "iPhone15Pro-1024", "price": 1499 },
            { "text": "iPhone 15 Plus, 128GB", "value": "iPhone15Plus-128", "price": 899 },
            { "text": "iPhone 15 Plus, 256GB", "value": "iPhone15Plus-256", "price": 999 },
            { "text": "iPhone 15 Plus, 512GB", "value": "iPhone15Plus-512", "price": 1199 },
            { "text": "iPhone 15, 128GB", "value": "iPhone15-128", "price": 799 },
            { "text": "iPhone 15, 256GB", "value": "iPhone15-256", "price": 899 },
            { "text": "iPhone 15, 512GB", "value": "iPhone15-512", "price": 1099 },
            { "text": "iPhone 14 Pro Max, 256GB", "value": "iPhone14ProMax-256", "price": 1099 },
            { "text": "iPhone 14 Pro Max, 512GB", "value": "iPhone14ProMax-512", "price": 1299 },
            { "text": "iPhone 14 Pro Max, 1TB", "value": "iPhone14ProMax-1024", "price": 1499 },
            { "text": "iPhone 14 Pro, 128GB", "value": "iPhone14Pro-128", "price": 899 },
            { "text": "iPhone 14 Pro, 256GB", "value": "iPhone14Pro-256", "price": 999 },
            { "text": "iPhone 14 Pro, 512GB", "value": "iPhone14Pro-512", "price": 1199 },
            { "text": "iPhone 14 Pro, 1TB", "value": "iPhone14Pro-1024", "price": 1399 },
            { "text": "iPhone 14 Plus, 128GB", "value": "iPhone14Plus-128", "price": 799 },
            { "text": "iPhone 14 Plus, 256GB", "value": "iPhone14Plus-256", "price": 899 },
            { "text": "iPhone 14 Plus, 512GB", "value": "iPhone14Plus-512", "price": 1099 },
            { "text": "iPhone 14, 128GB", "value": "iPhone14-128", "price": 699 },
            { "text": "iPhone 14, 256GB", "value": "iPhone14-256", "price": 799 },
            { "text": "iPhone 14, 512GB", "value": "iPhone14-512", "price": 999 }
          ],
          "totalType": "count",
          "totalFormat": "Total: {0}"
        },
        {
          "name": "price",
          "title": "Price",
          "cellType": "expression",
          "expression": "getItemPrice('phone_model')",
          "displayStyle": "currency"
        },
        {
          "name": "quantity",
          "title": "Quantity",
          "isRequired": true,
          "cellType": "text",
          "inputType": "number",
          "min": 1,
          "max": 100,
          "defaultValue": 1,
          "textUpdateMode": "onTyping",
          "enableIf": "{row.phone_model} notempty",
          "totalType": "sum",
          "totalFormat": "Total: {0}"
        },
        {
          "name": "total",
          "title": "Total",
          "cellType": "expression",
          "expression": "{row.quantity} * {row.price}",
          "displayStyle": "currency",
          "totalType": "sum",
          "totalDisplayStyle": "currency",
          "totalFormat": "Total: {0}"
        }
      ]
    },
    {
      "name": "vatPercentage",
      "type": "text",
      "title": "VAT (in %)",
      "inputType": "number",
      "min": 0,
      "max": 40,
      "defaultValue": 20,
      "textUpdateMode": "onTyping"
    },
    {
      "name": "vatTotal",
      "type": "expression",
      "title": "VAT",
      "expression": "{orders-total.total} * {vatPercentage} / 100",
      "displayStyle": "currency",
      "startWithNewLine": false
    },
    {
      "name": "total",
      "type": "expression",
      "title": "Total",
      "expression": "{orders-total.total} + {vatTotal}",
      "displayStyle": "currency",
      "startWithNewLine": false
    }
  ]
};
```

### `src/theme.js`

```js
export const themeJson = {};
```

### `package.json`

```json
{
  "dependencies": {
    "react": "latest",
    "react-dom": "latest",
    "survey-core": "latest",
    "survey-react-ui": "latest"
  },
  "devDependencies": {
    "react-scripts": "latest"
  }
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/form-library/examples/aggregate-data-within-form/angular.md)
- [Vue 3](https://surveyjs.io/form-library/examples/aggregate-data-within-form/vue3js.md)
- [jQuery](https://surveyjs.io/form-library/examples/aggregate-data-within-form/jquery.md)
- [Vanilla JS](https://surveyjs.io/form-library/examples/aggregate-data-within-form/vanillajs.md)
