Groups and master-detail
Groups
Section titled “Groups”A group adds a header and a footer around runs of rows that share a key. Add groups to a data region, outermost first:
{ "kind": "dataRegion", "id": "orders_region", "dataSource": "orders", "sort": [{ "expression": "row.date", "direction": "asc" }], "groups": [{ "id": "by_customer", "expression": "row.customer", "sortDirection": "asc", "header": { "id": "gh", "height": 8, "components": [ { "id": "gh1", "type": "text", "x": 0, "y": 1, "width": 186, "height": 6, "text": "{{ group.key }}" } ]}, "footer": { "id": "gf", "height": 8, "components": [ { "id": "gf1", "type": "text", "x": 134, "y": 1, "width": 52, "height": 6, "text": "{{ sum(group.rows, 'amount') }}" } ]} }], "detail": { "id": "row", "height": 6.5, "components": [] }}- The group expression is evaluated for each row; consecutive rows with an equal value form a group.
sortDirectionsorts the rows by the group key first:asc(default),desc, ornoneto group consecutive rows as they are.- Inside group bands:
group.key,group.rows,group.count,group.index,group.level. With nested groups,groupslists them outermost first. pageBreakBefore: trueon a group starts each group (after the first) on a new page.
import { ReportViewer } from '@ariana-reports/react';import { salesData, salesTemplate } from './report-data';
export default function ViewerGrouping() { return <ReportViewer template={salesTemplate} data={salesData} zoomMode="fitWidth" />;}<script setup lang="ts">import { ReportViewer } from '@ariana-reports/vue';import { salesData, salesTemplate } from './report-data';</script>
<template> <ReportViewer :template="salesTemplate" :data="salesData" zoom-mode="fitWidth" /></template>{ "schemaVersion": 1, "name": "Sales by customer", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "orders" } ], "styles": { "title": { "fontSize": 18, "fontWeight": "bold", "color": "#0f172a" }, "muted": { "fontSize": 9, "color": "#64748b" }, "th": { "fontSize": 9, "fontWeight": "bold", "color": "#ffffff", "backgroundColor": "#334155", "padding": 1.5 }, "td": { "fontSize": 9, "padding": 1.5, "border": { "width": 0.4, "color": "#e2e8f0", "style": "solid", "sides": [ "bottom" ] } }, "num": { "textAlign": "right" }, "sub": { "fontSize": 9, "fontWeight": "bold", "backgroundColor": "#e2e8f0", "padding": 1.5 } }, "reportHeader": { "id": "rh", "height": 16, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 9, "text": "Sales by customer", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 10, "width": 186, "height": 5, "text": "{{ count(orders) }} orders from {{ distinct(orders, \"customer\").length }} customers", "styleName": "muted" } ] }, "pageFooter": { "id": "pf", "height": 8, "components": [ { "id": "pf_n", "type": "text", "x": 0, "y": 2, "width": 186, "height": 5, "text": "Page {{ page.number }} of {{ page.count }}", "style": { "fontSize": 8, "color": "#64748b", "textAlign": "right" } } ] }, "body": [ { "kind": "dataRegion", "id": "orders_region", "dataSource": "orders", "sort": [ { "expression": "row.date", "direction": "asc" } ], "groups": [ { "id": "by_customer", "expression": "row.customer", "header": { "id": "gh", "height": 8, "components": [ { "id": "gh1", "type": "text", "x": 0, "y": 1, "width": 186, "height": 6, "text": "{{ group.key }}", "style": { "fontSize": 11, "fontWeight": "bold", "color": "#1d4ed8", "padding": 1 } } ] }, "footer": { "id": "gf", "height": 8, "components": [ { "id": "gf1", "type": "text", "x": 0, "y": 1, "width": 134, "height": 6, "text": "Subtotal ({{ group.count }} orders)", "styleName": "sub" }, { "id": "gf2", "type": "text", "x": 134, "y": 1, "width": 52, "height": 6, "text": "{{ sum(group.rows, \"amount\") }}", "styleName": "sub", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] } } ], "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 22, "height": 7, "text": "Order", "styleName": "th" }, { "id": "h2", "type": "text", "x": 22, "y": 0, "width": 30, "height": 7, "text": "Date", "styleName": "th" }, { "id": "h3", "type": "text", "x": 52, "y": 0, "width": 82, "height": 7, "text": "Product", "styleName": "th" }, { "id": "h4", "type": "text", "x": 134, "y": 0, "width": 52, "height": 7, "text": "Amount", "styleName": "th", "style": { "textAlign": "right" } } ] }, "detail": { "id": "row", "height": 6.5, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 22, "height": 6.5, "text": "#{{ row.id }}", "styleName": "td" }, { "id": "c2", "type": "text", "x": 22, "y": 0, "width": 30, "height": 6.5, "text": "{{ row.date }}", "styleName": "td", "format": { "type": "date", "pattern": "dd MMM yyyy" } }, { "id": "c3", "type": "text", "x": 52, "y": 0, "width": 82, "height": 6.5, "text": "{{ row.product }}", "styleName": "td" }, { "id": "c4", "type": "text", "x": 134, "y": 0, "width": 52, "height": 6.5, "text": "{{ row.amount }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] }, "footer": { "id": "foot", "height": 10, "components": [ { "id": "f1", "type": "text", "x": 0, "y": 2, "width": 134, "height": 7, "text": "Grand total", "style": { "fontSize": 11, "fontWeight": "bold", "backgroundColor": "#1e293b", "color": "#fff", "padding": 1.5 } }, { "id": "f2", "type": "text", "x": 134, "y": 2, "width": 52, "height": 7, "text": "{{ sum(rows, \"amount\") }}", "style": { "fontSize": 11, "fontWeight": "bold", "backgroundColor": "#1e293b", "color": "#fff", "padding": 1.5, "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] } } ]}{ "orders": [ { "id": 1001, "customer": "Contoso Ltd", "date": "2026-01-08", "product": "Cloud backup", "amount": 480 }, { "id": 1002, "customer": "Fabrikam", "date": "2026-01-11", "product": "USB-C dock", "amount": 129.9 }, { "id": 1003, "customer": "Contoso Ltd", "date": "2026-01-15", "product": "Support plan", "amount": 1200 }, { "id": 1004, "customer": "Northwind", "date": "2026-01-19", "product": "Monitor stand", "amount": 54.5 }, { "id": 1005, "customer": "Fabrikam", "date": "2026-02-02", "product": "Headset", "amount": 89 }, { "id": 1006, "customer": "Northwind", "date": "2026-02-05", "product": "Webcam HD", "amount": 75.25 } ]}Master-detail
Section titled “Master-detail”A child region renders after each row of its parent. It reads its rows from an array field of the parent row (relation), or from another data source (dataSource with a filter).
{ "kind": "dataRegion", "id": "orders_region", "dataSource": "orders", "detail": { "id": "order", "height": 9, "components": [] }, "children": [{ "kind": "dataRegion", "id": "items_region", "relation": "items", "detail": { "id": "item", "height": 6, "components": [] }, "footer": { "id": "items_total", "height": 9, "components": [ { "id": "t", "type": "text", "x": 161, "y": 1, "width": 25, "height": 6, "text": "{{ sum(rows, r => r.qty * r.price) }}" } ]} }]}Inside the child, row is the item and parent is the order, so {{ parent.id }} works in item bands. Children can have children of their own.
import { ReportViewer } from '@ariana-reports/react';import { ordersData, ordersTemplate } from './report-data';
export default function ViewerMasterDetail() { return <ReportViewer template={ordersTemplate} data={ordersData} zoomMode="fitWidth" />;}<script setup lang="ts">import { ReportViewer } from '@ariana-reports/vue';import { ordersData, ordersTemplate } from './report-data';</script>
<template> <ReportViewer :template="ordersTemplate" :data="ordersData" zoom-mode="fitWidth" /></template>{ "schemaVersion": 1, "name": "Orders with items", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "orders" } ], "styles": { "title": { "fontSize": 18, "fontWeight": "bold", "color": "#0f172a" }, "muted": { "fontSize": 9, "color": "#64748b" }, "th": { "fontSize": 9, "fontWeight": "bold", "color": "#ffffff", "backgroundColor": "#334155", "padding": 1.5 }, "td": { "fontSize": 9, "padding": 1.5, "border": { "width": 0.4, "color": "#e2e8f0", "style": "solid", "sides": [ "bottom" ] } }, "num": { "textAlign": "right" }, "sub": { "fontSize": 9, "fontWeight": "bold", "backgroundColor": "#e2e8f0", "padding": 1.5 } }, "reportHeader": { "id": "rh", "height": 14, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 9, "text": "Orders with items", "styleName": "title" } ] }, "pageFooter": { "id": "pf", "height": 8, "components": [ { "id": "pf_n", "type": "text", "x": 0, "y": 2, "width": 186, "height": 5, "text": "Page {{ page.number }} of {{ page.count }}", "style": { "fontSize": 8, "color": "#64748b", "textAlign": "right" } } ] }, "body": [ { "kind": "dataRegion", "id": "orders_region", "dataSource": "orders", "detail": { "id": "order", "height": 9, "components": [ { "id": "o1", "type": "text", "x": 0, "y": 2, "width": 40, "height": 6, "text": "Order {{ row.id }}", "style": { "fontSize": 11, "fontWeight": "bold", "color": "#1d4ed8" } }, { "id": "o2", "type": "text", "x": 40, "y": 2, "width": 80, "height": 6, "text": "{{ row.customer }}", "style": { "fontSize": 11, "fontWeight": "bold" } }, { "id": "o3", "type": "text", "x": 120, "y": 2, "width": 66, "height": 6, "text": "{{ row.date }}", "style": { "fontSize": 9, "color": "#64748b", "textAlign": "right" }, "format": { "type": "date", "pattern": "d MMMM yyyy" } } ] }, "children": [ { "kind": "dataRegion", "id": "items_region", "relation": "items", "detail": { "id": "item", "height": 6, "components": [ { "id": "i1", "type": "text", "x": 6, "y": 0, "width": 26, "height": 6, "text": "{{ row.sku }}", "styleName": "td" }, { "id": "i2", "type": "text", "x": 32, "y": 0, "width": 84, "height": 6, "text": "{{ row.name }}", "styleName": "td" }, { "id": "i3", "type": "text", "x": 116, "y": 0, "width": 20, "height": 6, "text": "{{ row.qty }}", "styleName": "td", "style": { "textAlign": "right" } }, { "id": "i4", "type": "text", "x": 136, "y": 0, "width": 25, "height": 6, "text": "{{ row.price }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } }, { "id": "i5", "type": "text", "x": 161, "y": 0, "width": 25, "height": 6, "text": "{{ row.qty * row.price }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] }, "footer": { "id": "items_total", "height": 9, "components": [ { "id": "t1", "type": "text", "x": 116, "y": 1.5, "width": 45, "height": 6, "text": "Order total", "styleName": "sub", "style": { "textAlign": "right" } }, { "id": "t2", "type": "text", "x": 161, "y": 1.5, "width": 25, "height": 6, "text": "{{ sum(rows, r => r.qty * r.price) }}", "styleName": "sub", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] } } ] } ]}{ "orders": [ { "id": "A-2041", "customer": "Contoso Ltd", "date": "2026-03-02", "items": [ { "sku": "KB-100", "name": "Mechanical keyboard", "qty": 4, "price": 149 }, { "sku": "MS-020", "name": "Wireless mouse", "qty": 4, "price": 35.5 }, { "sku": "DK-300", "name": "USB-C dock", "qty": 2, "price": 129.9 } ] }, { "id": "A-2042", "customer": "Fabrikam", "date": "2026-03-03", "items": [ { "sku": "HS-410", "name": "Headset", "qty": 10, "price": 89 }, { "sku": "WC-220", "name": "Webcam HD", "qty": 10, "price": 75.25 } ] }, { "id": "A-2043", "customer": "Northwind", "date": "2026-03-07", "items": [ { "sku": "MN-501", "name": "Monitor stand", "qty": 6, "price": 54.5 }, { "sku": "DL-009", "name": "Desk lamp", "qty": 6, "price": 42 }, { "sku": "LS-777", "name": "Laptop sleeve", "qty": 6, "price": 39 }, { "sku": "SP-001", "name": "Support plan (1 year)", "qty": 1, "price": 1200 } ] } ]}