In the web world, the data grid is arguably the most indispensable UI tool for presenting business data in a clear and meaningful way to users. When working with grid widgets in Nitro App Builder (NAB), customizing how data is presented at the summary level can help provide even more clarity. As described in a previous blog post, custom renderers inside grid cells make it possible to tailor the display of regular, subtotal and grand total cells in a grid.
While it’s always been possible to distinguish a regular cell from an aggregate (subtotal/grand total) cell, there has never been an easy way to determine when rendering is being applied to a cell in a subtotal row versus a grand total for the grid. Fortunately, as of Valence 6.3 build (6.3.20250821.0) this shortcoming has been addressed through the introduction of a new group-check property.

So in this month’s tip, we’ll recap some of the prior blog post, but this time zeroing in on custom renderers at the aggregate level, focusing on how to distinguish subtotal rows (e.g., customer sales by country) from the grand total row and allowing for different rendering logic to be applied at each level.
Why custom subtotal renderers matter
Whether you’re summarizing sales data by location or analyzing other business metrics, NAB grids allow you to aggregate numeric values with ease — simply check a box to enable standard summary functions like sum, average, or count, and another box to group them. However, standard summaries expressed as mere numbers may not provide the best context or formatting, particularly when you’re looking to distinguish between subtotals (e.g., total sales per country) versus the grand total (e.g., total sales across all countries).
Custom subtotal renderers can address this by giving developers fine-grained control over how summary rows are calculated and displayed. For example, in a sales grid grouped by customer country, you might want subtotal rows to display “Total Sales for [Country]” with specific formatting, while the grand total row might say “Global Sales Total” with a distinct style or calculation. This differentiation enhances readability, reduces confusion, and aligns the grid’s output with business requirements. Additionally, custom renderers allow you to incorporate data from other columns, apply conditional logic, or add HTML formatting for a polished user experience.
The scenario: Summarizing sales by country
Let’s consider this practical example: You’re building a NAB grid that lists sales totals for each active customer, sorted and grouped by country. Each row shows basic customer information with a column for total sales. You want:
- Subtotal rows to display the total sales for each country, labeled as “Total Sales for [Country]” with currency formatting. This way your users won’t have to look higher up the list to the start of the group to see the country corresponding to the subtotal.
- Grand total row to show the sum of all sales across all countries, labeled as “Global Sales Total” with bold text for emphasis.
In typical applications using default settings, the grid would apply the same summary function (e.g., sum) to both the subtotal and grand total rows, with no major distinguishing difference between them. You can add some clarity and flair using custom subtotal renderers to inject specific text, formatting, or logic to make the different types of aggregate rows stand out.
How to implement custom subtotal renderers
Let’s walk through adding a custom subtotal renderer in a NAB grid, focusing on distinguishing subtotal and grand total rows. We’ll assume you’ve already set up a grid widget with a data source containing sales data that includes columns for country and total sale amounts for each customer. For the example that follows we’ll use the trusty DEMOCMAST file included with Valence for demonstration purposes.
1: Configure the grid for grouping and summarization
- In Nitro App Builder, create or edit your grid widget tied to a data source with customer sales data and be sure all the appropriate columns are included in the grid, particularly the country and sales (for DEMOCMAST it’s columns CCOUNTRY and CYTDSALES).
- In the grid’s general configuration (second tab on the left), open up the “Data” section on the right carousel menu and set up the CCOUNTRY field for grouping.

- Next, in the grid’s column configuration (first tab on the left), locate the CYTDSALES column and enable summarization on it by clicking the calculator icon and checking the “Total” box, which will cause the grid to include subtotal rows for each country group and a grand total row.

2: Add a custom renderer
- In the CYTDSALES column settings, click on the Renderer option <> so you can define custom JavaScript logic to control how the cell’s value is displayed. This will open a pop-up window for the renderer code.
- Write your custom renderer function, with logic to differentiate between subtotal and grand total rows. The renderer function receives parameters that include value (the cell’s value), rec (the record data), and, whenver a summary function is active for the cell, a parameter called summary (an object with summary row information). The new summary.isGroup property is key — it will be set to true for subtotal rows, and false for the grand total row, as we’ll see below…

Let’s take a closer look at each line in this renderer:
v = Ext.util.Format.currency(v);Here we’re taking the raw numeric value passed in (v) and using an Ext JS utility function to format it as currency ($0,000.00). This is just one of many ways to achieve this formatting like this using JavaScript, and you can use the “Help me” AI assistant to ask for additional approaches. In fact, you could use “Help me” to write this entire renderer for you, which we encourage you to try.
if (summary.isRow) {This if block is conditioned on summary.isRow being true, which will be the case whenever your custom renderer is being executed inside a group subtotal or grand total. Regular rows will thus skip over this section.
if (summary.isGroup) {And here we get to the recently introduced property for distinguishing between group summary and grand total rows. If summary.isGroup is true, then you know your renderer is working on the totals for a group (customer country in this case). You can thus return a value that takes this into account, like this…
return `Total for ${summary.group.get('CCOUNTRY')} : ${v}`;Here we’re returning the final value for this cell, and there’s a nice little JavaScript lesson included in this one: The two segments consisting of a dollar sign followed by brackets — ${xxx} — are JavaScript shorthand for pulling a variable or expression (xxx) into the string. Key to this working is that the string is encapsulated not with standard single or double quotes, but rather with slanted single quotes, which are referred to in the JavaScript world as template literals. The template literals turn this into a special kind of string where any embedded ${xxx} expressions are automatically evaluated on-the-fly, making for a bit less typing and easier interpretation, versus the conventional alternative of terminating the string, concatenating a value, resuming the string and so on; The summary.group.get(‘field_name’) is used to return the country that is being grouped (this is included in the list of commonly used expressions at the bottom of the renderer window); Finally, ${v} inserts our passed-in sales value (v) that we previously formatted into a currency amount.
} else {
return `<b>Grand Total : ${v}</b>`;
}This is the else clause to our summary.isGroup test, indicating the customer renderer is executing inside the grand total line. Here we simply show the formatted “Grand Total” value in bold to clearly distinguish it from the group subtotals.
}
return v; Finally we have our catch-all at the end of the renderer. If neither of the prior return statements have been hit and we come to this line, it means we’re on a regular non-aggregate line. So no need to add any text, we just return the currency-formatted value and we’re done. ]
And here’s the result of our custom renderer effort…

3: Consider further enhancements with formatting, tooltips, etc.
To make your grid columns even more user-friendly, you could:
- Add HTML formatting (e.g., <b>, <i>, or <div> tags) to style the text, as done with the grand total
- Change colors to draw attention to low or high values
- Include tooltips for additional context using a data-qtip attribute
Again, be sure to try the “Help me” AI assistant to give you JavaScript code for any of the above scenarios. All you need to do is give it a few instructions and you’ll be amazed at how quickly you can achieve some pro-level formatting without hours of googling and trial-and-error hacking.
![CNX_logo [Converted]](https://cnxcorp.com/wp-content/uploads/2023/05/CNX_logo-Converted-2.png)
![CNX_logo [Converted]](https://cnxcorp.com/wp-content/uploads/2023/05/CNX_logo-Converted.png)