The Pivot Table widget enables the dynamic grouping and aggregation of object data and then displays this aggregated data in tabular form. Module builders configuring a Pivot Table widget can use features including:
The example below shows a configured Pivot Table widget displaying Flight Alerts data and filtering a downstream Object list widget:

When configuring a pivot table, builders can either derive data from objects or function output.
The example below shows the initial state of an object-backed pivot table before configuration. The widget's configuration panel shows the initial input Base object set set to Flight Alert: All.

The Pivot Table widget has the following core configuration options:
Total row will be the result of performing the multi-step aggregation on all the raw values of the objects before each aggregation.The Pivot Table widget supports a maximum of seven row groupings. If you need to work with more groupings, consider adding hidden groupings to your table configuration. This approach allows users to swap between hidden groupings in the UI, effectively managing more groupings than the limit while maintaining performance.
The Pivot Table widget supports the following keyboard shortcuts for working with selected cells:
Cmd+C (macOS) or Ctrl+C (Windows) to copy the selected cells as tab-separated values. The output includes row groupings, aggregation values, or both, depending on the selection.Shift+Left and Shift+Right to refine your selection between full rows, row groupings only, and aggregation values only.A function-backed pivot table derives its data from the output of a function.
This approach is useful for the following use cases:
values, which holds the pivot table values.TypeScript v1 and TypeScript v2 require the same output shape for a function-backed pivot table: an array of structs, where every struct contains a field named values. The struct declaration is the same in both versions; the imports and the function declaration differ, as shown in the tabs below.
Below is an example of a struct definition and function declaration that can be used for a function-backed pivot table.
In this struct definition:
region, productType, productName, and year are fields used for grouping.totalSales and estimatedSales are the values displayed in the pivot table cells.Both versions declare the struct as a custom type using the interface keyword. TypeScript v1 registers the function with the @Function() decorator on a class method and imports Integer from @foundry/functions-api. TypeScript v2 registers the function as the default export of the file and imports Integer from @osdk/functions.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22import { Function, Integer } from "@foundry/functions-api"; interface SalesData { region?: string; year?: string; productType?: string; productName?: string; // Values object containing the metrics values: { totalSales: Integer; estimatedSales: Integer; } }; export class MyFunctions { @Function() public salesFunctionBackedPivotTable(): SalesData[] { // Your implementation here return []; } }
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19import { Integer } from "@osdk/functions"; interface SalesData { region?: string; year?: string; productType?: string; productName?: string; // Values object containing the metrics values: { totalSales: Integer; estimatedSales: Integer; } }; export default function salesFunctionBackedPivotTable(): SalesData[] { // Your implementation here return []; }
After selecting a function in the dropdown, builders can choose:
Once configured, the pivot table will render with the data returned from your function:
Function-backed pivot tables support displaying totals. To render a total, return a struct in your list that follows the guidelines below. For the examples below, assume that region and productType are the row grouping fields and year is the column grouping field.
Row totals: To represent a sum of all rows (row total), omit the row grouping fields in the data point.
Example: A data point representing the total for 2021:
Copied!1 2 3 4 5 6 7{ year: "2021"; values: { totalSales: 622000; estimatedSales: 57000; } };
Column totals: To represent a sum of all columns (column total), omit the column grouping fields in the data point.
Example: A data point representing the total for EU and Clothing:
Copied!1 2 3 4 5 6 7 8{ region: "EU"; productType: "Clothing"; values: { totalSales: 57000; estimatedSales: 57000; } }
Grand totals: To represent a grand total, omit all grouping fields.
Copied!1 2 3 4 5 6{ values: { totalSales: 3147000; estimatedSales: 3160000; } }
Null buckets are useful for representing missing or undefined data.
To create a null bucket:
undefined for the bucket's value.Avoid using empty strings ('') for null or missing values in grouping fields. Workshop interprets empty strings as if the field is omitted, causing records with empty strings to roll up into subtotal rows rather than appear as individual grouping rows. Always use undefined for true null buckets.
Below is an example:
Copied!1 2 3 4 5 6 7interface SiteData { site?: string; part?: string | undefined; // Note the explicit undefined type values: { quantity: Double; } }
Copied!1 2 3 4 5 6 7{ "part": undefined, "source": "SourceA", "values": { "quantity": 100 } }
Omitting a field is different from passing undefined. Omitting a field creates a total, while undefined creates a null bucket.
Expandable rows allow users to drill down into more detailed data.
To implement expandable rows:
Considering the following interface, we would select productName and productType as our expandable rows in the configuration options:
Copied!1 2 3 4 5 6 7 8 9 10interface SalesData { region: string; year: string; productType?: string; productName?: string; values: { totalSales: Integer; estimatedSales: Integer; } };
Below are examples of three levels of expansion:
region level only.Copied!1 2 3 4 5 6 7 8 9[ { "region": "NA", "year": "2021", "values": { "totalSales": 30000 } } ]
region and productType.Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26[ { "region": "NA", "year": "2021", "productType": "Clothing", "values": { "totalSales": 90000 } }, { "region": "NA", "year": "2021", "productType": "Electronics", "values": { "totalSales": 150000 } }, { "region": "NA", "year": "2021", "productType": "Furniture", "values": { "totalSales": 60000 } } ]
region, productType, and productName.Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29[ { "region": "NA", "year": "2021", "productType": "Electronics", "productName": "ProductA", "values": { "totalSales": 5000 } }, { "region": "NA", "year": "2021", "productType": "Electronics", "productName": "ProductB", "values": { "totalSales": 5000 } }, { "region": "NA", "year": "2021", "productType": "Electronics", "productName": "ProductC", "values": { "totalSales": 5000 } } ]
The output selection of a function-backed pivot table can be written to a struct variable. The struct fields are derived from the function's output.
The Pivot Table widget has the following display and styling options: