Live demos
Each demo runs live. Use the React and Vue tabs to see the code for each framework; your choice is remembered across the site. The Template JSON and Data JSON tabs show what the report is made of. Want to change something? Open the playground.
Scrolling through pages
Section titled “Scrolling through pages”All pages in one scrollable column. Only the pages you can see are rendered, so 140 rows over several pages stay fast.
import { ReportViewer } from '@ariana-reports/react';import { productsData, productsTemplate } from './report-data';
export default function ViewerBasic() { return <ReportViewer template={productsTemplate} data={productsData} zoomMode="fitWidth" />;}<script setup lang="ts">import { ReportViewer } from '@ariana-reports/vue';import { productsData, productsTemplate } from './report-data';</script>
<template> <ReportViewer :template="productsTemplate" :data="productsData" zoom-mode="fitWidth" /></template>{ "schemaVersion": 1, "name": "Product catalog", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "products" } ], "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": 18, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 9, "text": "Product catalog", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 10, "width": 186, "height": 5, "text": "{{ count(products) }} products · printed {{ formatDate(today(), \"d MMMM yyyy\") }}", "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": "list", "dataSource": "products", "repeatHeaderOnEachPage": true, "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 28, "height": 7, "text": "SKU", "styleName": "th" }, { "id": "h2", "type": "text", "x": 28, "y": 0, "width": 72, "height": 7, "text": "Product", "styleName": "th" }, { "id": "h3", "type": "text", "x": 100, "y": 0, "width": 34, "height": 7, "text": "Category", "styleName": "th" }, { "id": "h4", "type": "text", "x": 134, "y": 0, "width": 26, "height": 7, "text": "Price", "styleName": "th", "style": { "textAlign": "right" } }, { "id": "h5", "type": "text", "x": 160, "y": 0, "width": 26, "height": 7, "text": "In stock", "styleName": "th", "style": { "textAlign": "right" } } ] }, "detail": { "id": "row", "height": 6.5, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 28, "height": 6.5, "text": "{{ row.sku }}", "styleName": "td" }, { "id": "c2", "type": "text", "x": 28, "y": 0, "width": 72, "height": 6.5, "text": "{{ row.name }}", "styleName": "td" }, { "id": "c3", "type": "text", "x": 100, "y": 0, "width": 34, "height": 6.5, "text": "{{ row.category }}", "styleName": "td" }, { "id": "c4", "type": "text", "x": 134, "y": 0, "width": 26, "height": 6.5, "text": "{{ row.price }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } }, { "id": "c5", "type": "text", "x": 160, "y": 0, "width": 26, "height": 6.5, "text": "{{ row.stock }}", "styleName": "td", "style": { "textAlign": "right" }, "conditions": [ { "expression": "row.stock < 10", "style": { "color": "#b91c1c", "fontWeight": "bold" } } ] } ] }, "footer": { "id": "foot", "height": 8, "components": [ { "id": "f1", "type": "text", "x": 0, "y": 1.5, "width": 134, "height": 6, "text": "Total stock value", "styleName": "sub" }, { "id": "f2", "type": "text", "x": 134, "y": 1.5, "width": 52, "height": 6, "text": "{{ sum(rows, r => r.price * r.stock) }}", "styleName": "sub", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] } } ]}{ "products": [ { "sku": "SKU-1000", "name": "Wireless mouse 1", "category": "Hardware", "price": 12, "stock": 0 }, { "sku": "SKU-1007", "name": "Mechanical keyboard 1", "category": "Software", "price": 49.99, "stock": 13 }, { "sku": "SKU-1014", "name": "USB-C dock 1", "category": "Services", "price": 87.98, "stock": 26 }, { "sku": "SKU-1021", "name": "Webcam HD 1", "category": "Accessories", "price": 123, "stock": 39 }, { "sku": "SKU-1028", "name": "Monitor stand 1", "category": "Hardware", "price": 160.99, "stock": 52 }, { "sku": "SKU-1035", "name": "Laptop sleeve 1", "category": "Software", "price": 18.98, "stock": 65 } ]}Groups with subtotals
Section titled “Groups with subtotals”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”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 } ] } ]}Conditional styles
Section titled “Conditional styles”import { ReportViewer } from '@ariana-reports/react';import { invoicesData, invoicesTemplate } from './report-data';
export default function ViewerConditional() { return <ReportViewer template={invoicesTemplate} data={invoicesData} zoomMode="fitWidth" />;}<script setup lang="ts">import { ReportViewer } from '@ariana-reports/vue';import { invoicesData, invoicesTemplate } from './report-data';</script>
<template> <ReportViewer :template="invoicesTemplate" :data="invoicesData" zoom-mode="fitWidth" /></template>{ "schemaVersion": 1, "name": "Invoice status", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "invoices" } ], "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": 22, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 9, "text": "Invoice status", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 10, "width": 186, "height": 10, "text": "{{ count(invoices, r => r.status === \"overdue\") }} overdue invoices, {{ formatCurrency(sum(invoices, r => r.status === \"overdue\" ? r.amount : 0), \"USD\") }} outstanding", "styleName": "muted", "style": { "fontSize": 10 }, "conditions": [ { "expression": "invoices.some(r => r.status === \"overdue\")", "style": { "color": "#b91c1c" } } ] } ] }, "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": "list", "dataSource": "invoices", "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 30, "height": 7, "text": "Invoice", "styleName": "th" }, { "id": "h2", "type": "text", "x": 30, "y": 0, "width": 60, "height": 7, "text": "Client", "styleName": "th" }, { "id": "h3", "type": "text", "x": 90, "y": 0, "width": 30, "height": 7, "text": "Due", "styleName": "th" }, { "id": "h4", "type": "text", "x": 120, "y": 0, "width": 36, "height": 7, "text": "Amount", "styleName": "th", "style": { "textAlign": "right" } }, { "id": "h5", "type": "text", "x": 156, "y": 0, "width": 30, "height": 7, "text": "Status", "styleName": "th", "style": { "textAlign": "center" } } ] }, "detail": { "id": "row", "height": 7, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 30, "height": 7, "text": "{{ row.no }}", "styleName": "td" }, { "id": "c2", "type": "text", "x": 30, "y": 0, "width": 60, "height": 7, "text": "{{ row.client }}", "styleName": "td" }, { "id": "c3", "type": "text", "x": 90, "y": 0, "width": 30, "height": 7, "text": "{{ row.due }}", "styleName": "td", "format": { "type": "date", "pattern": "dd MMM yyyy" } }, { "id": "c4", "type": "text", "x": 120, "y": 0, "width": 36, "height": 7, "text": "{{ row.amount }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" }, "conditions": [ { "expression": "row.amount >= 5000", "style": { "fontWeight": "bold" } } ] }, { "id": "c5", "type": "text", "x": 156, "y": 0, "width": 30, "height": 7, "text": "{{ upper(row.status) }}", "styleName": "td", "style": { "textAlign": "center", "fontWeight": "bold", "fontSize": 8 }, "conditions": [ { "expression": "row.status === \"paid\"", "style": { "color": "#15803d", "backgroundColor": "#dcfce7" } }, { "expression": "row.status === \"overdue\"", "style": { "color": "#b91c1c", "backgroundColor": "#fee2e2" } }, { "expression": "row.status === \"open\"", "style": { "color": "#a16207", "backgroundColor": "#fef9c3" } } ] } ] } } ]}{ "invoices": [ { "no": "INV-0412", "client": "Contoso Ltd", "due": "2026-02-01", "amount": 4200, "status": "paid" }, { "no": "INV-0413", "client": "Fabrikam", "due": "2026-02-15", "amount": 980.5, "status": "overdue" }, { "no": "INV-0414", "client": "Northwind", "due": "2026-03-01", "amount": 15250, "status": "open" }, { "no": "INV-0415", "client": "Tailspin", "due": "2026-03-12", "amount": 310, "status": "paid" }, { "no": "INV-0416", "client": "Litware", "due": "2026-03-20", "amount": 7800, "status": "overdue" }, { "no": "INV-0417", "client": "Contoso Ltd", "due": "2026-04-02", "amount": 2650, "status": "open" } ]}Formatted text with HTML tags
Section titled “Formatted text with HTML tags”import { ReportViewer } from '@ariana-reports/react';import { notesData, notesTemplate } from './report-data';
export default function ViewerHtml() { return <ReportViewer template={notesTemplate} data={notesData} zoomMode="fitWidth" />;}<script setup lang="ts">import { ReportViewer } from '@ariana-reports/vue';import { notesData, notesTemplate } from './report-data';</script>
<template> <ReportViewer :template="notesTemplate" :data="notesData" zoom-mode="fitWidth" /></template>{ "schemaVersion": 1, "name": "Account notes", "unit": "mm", "page": { "size": "A5", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "tasks" }, { "name": "customer" } ], "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 }, "note": { "fontSize": 9.5, "padding": 1.5 } }, "reportHeader": { "id": "rh", "height": 22, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 124, "height": 9, "text": "Account notes", "styleName": "title" }, { "id": "who", "type": "text", "x": 0, "y": 10, "width": 124, "height": 10, "text": "<b>{{ customer.name }}</b><br>Contact: {{ customer.contact }}", "allowHtml": true, "canGrow": true, "styleName": "muted", "style": { "fontSize": 10 } } ] }, "body": [ { "kind": "dataRegion", "id": "tasks_region", "dataSource": "tasks", "detail": { "id": "task", "height": 24, "components": [ { "id": "n1", "type": "text", "x": 0, "y": 1, "width": 124, "height": 6, "text": "{{ rowNumber }}. {{ row.title }}", "allowHtml": true, "style": { "fontSize": 11, "fontWeight": "bold" } }, { "id": "n2", "type": "text", "x": 5, "y": 8, "width": 119, "height": 14, "text": "{{ row.note }}", "allowHtml": true, "canGrow": true, "styleName": "note" } ] } } ]}{ "customer": { "name": "Contoso Ltd", "contact": "Ada Lovelace" }, "tasks": [ { "title": "Renew <b>support plan</b>", "note": "Expires <font color=\"#b91c1c\">31 March</font>.<br>Call before the <u>end of the month</u>." }, { "title": "Send <i>price list</i>", "note": "Include the <b>new</b> hardware range and mention the <s>old</s> discount of <b>15%</b>." }, { "title": "Prepare <span style=\"color:#1d4ed8;font-weight:bold\">onboarding</span> call", "note": "Agenda:<br>1. Accounts<br>2. Training<br>3. Q&A" } ]}Persian: digits, Jalali dates and interface
Section titled “Persian: digits, Jalali dates and interface”import { useEffect, useState } from 'react';import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';import { ReportViewer } from '@ariana-reports/react';import { persianData, persianTemplate } from './report-data';import { loadPersianFonts } from './fonts';
export default function ViewerPersian() { // The PDF needs the font files: register them in `pdf.fonts`, and measure text with them so line breaks match. const [fonts, setFonts] = useState<{ fonts: FontRegistration[]; measurer: TextMeasurer }>(); useEffect(() => { loadPersianFonts().then(async (fonts) => setFonts({ fonts, measurer: await createFontMeasurer(fonts) })); }, []); if (!fonts) return null; return <ReportViewer template={persianTemplate} data={persianData} zoomMode="fitWidth" uiLocale="fa" measurer={fonts.measurer} pdf={{ fonts: fonts.fonts }} />;}<script setup lang="ts">import { onMounted, shallowRef } from 'vue';import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';import { ReportViewer } from '@ariana-reports/vue';import { persianData, persianTemplate } from './report-data';import { loadPersianFonts } from './fonts';
// The PDF needs the font files: register them in `pdf.fonts`, and measure text with them so line breaks match.const fonts = shallowRef<{ fonts: FontRegistration[]; measurer: TextMeasurer }>();onMounted(async () => { const files = await loadPersianFonts(); fonts.value = { fonts: files, measurer: await createFontMeasurer(files) };});</script>
<template> <ReportViewer v-if="fonts" :template="persianTemplate" :data="persianData" zoom-mode="fitWidth" ui-locale="fa" :measurer="fonts.measurer" :pdf="{ fonts: fonts.fonts }" /></template>{ "schemaVersion": 1, "name": "گزارش فروش", "unit": "mm", "locale": "fa-IR", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "sales" } ], "styles": { "title": { "fontFamily": "Vazirmatn", "fontSize": 18, "fontWeight": "bold", "textAlign": "right" }, "th": { "fontFamily": "Vazirmatn", "fontSize": 9, "fontWeight": "bold", "color": "#fff", "backgroundColor": "#334155", "padding": 1.5, "textAlign": "right" }, "td": { "fontFamily": "Vazirmatn", "fontSize": 9.5, "padding": 1.5, "textAlign": "right", "border": { "width": 0.4, "color": "#e2e8f0", "style": "solid", "sides": [ "bottom" ] } }, "sub": { "fontFamily": "Vazirmatn", "fontSize": 10, "fontWeight": "bold", "backgroundColor": "#e2e8f0", "padding": 1.5, "textAlign": "right" } }, "reportHeader": { "id": "rh", "height": 18, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 10, "text": "گزارش فروش", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 11, "width": 186, "height": 5, "text": "{{ count(sales) }} سفارش · تاریخ گزارش: {{ formatDate(today(), \"d MMMM yyyy\", \"persian\") }}", "style": { "fontFamily": "Vazirmatn", "fontSize": 9.5, "color": "#64748b", "textAlign": "right" } } ] }, "body": [ { "kind": "dataRegion", "id": "list", "dataSource": "sales", "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 40, "height": 7, "text": "تاریخ", "styleName": "th" }, { "id": "h2", "type": "text", "x": 40, "y": 0, "width": 40, "height": 7, "text": "قیمت واحد", "styleName": "th" }, { "id": "h3", "type": "text", "x": 80, "y": 0, "width": 20, "height": 7, "text": "تعداد", "styleName": "th" }, { "id": "h4", "type": "text", "x": 100, "y": 0, "width": 36, "height": 7, "text": "کالا", "styleName": "th" }, { "id": "h5", "type": "text", "x": 136, "y": 0, "width": 50, "height": 7, "text": "مشتری", "styleName": "th" } ] }, "detail": { "id": "row", "height": 7, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 40, "height": 7, "text": "{{ row.date }}", "styleName": "td", "format": { "type": "date", "pattern": "yyyy/MM/dd", "calendar": "persian" } }, { "id": "c2", "type": "text", "x": 40, "y": 0, "width": 40, "height": 7, "text": "{{ row.price }}", "styleName": "td", "format": { "type": "number", "decimals": 0, "thousandsSeparator": true } }, { "id": "c3", "type": "text", "x": 80, "y": 0, "width": 20, "height": 7, "text": "{{ row.qty }}", "styleName": "td" }, { "id": "c4", "type": "text", "x": 100, "y": 0, "width": 36, "height": 7, "text": "{{ row.product }}", "styleName": "td" }, { "id": "c5", "type": "text", "x": 136, "y": 0, "width": 50, "height": 7, "text": "{{ row.customer }}", "styleName": "td" } ] }, "footer": { "id": "foot", "height": 10, "components": [ { "id": "f1", "type": "text", "x": 0, "y": 2, "width": 80, "height": 7, "text": "{{ sum(rows, r => r.qty * r.price) }}", "styleName": "sub", "format": { "type": "number", "decimals": 0, "thousandsSeparator": true } }, { "id": "f2", "type": "text", "x": 80, "y": 2, "width": 106, "height": 7, "text": "جمع کل (ریال)", "styleName": "sub" } ] } } ]}{ "sales": [ { "customer": "شرکت آریا", "product": "لپتاپ", "qty": 12, "price": 485000000, "date": "2026-03-21" }, { "customer": "فروشگاه پارس", "product": "مانیتور", "qty": 30, "price": 128500000, "date": "2026-03-23" }, { "customer": "شرکت آریا", "product": "کیبورد", "qty": 40, "price": 9800000, "date": "2026-03-25" }, { "customer": "دانشگستر", "product": "هدست", "qty": 25, "price": 17400000, "date": "2026-04-01" }, { "customer": "فروشگاه پارس", "product": "وبکم", "qty": 18, "price": 12300000, "date": "2026-04-03" } ]}Matching your theme
Section titled “Matching your theme”import { useState } from 'react';import { DARK_THEME, ReportViewer, themeFromMui } from '@ariana-reports/react';import { salesData, salesTemplate } from './report-data';
// Any object shaped like a Material UI theme works, so in a MUI app pass useTheme() directly.const grape = themeFromMui({ palette: { mode: 'light', primary: { main: '#7b1fa2' }, background: { default: '#f3e5f5', paper: '#ffffff' } }, shape: { borderRadius: 14 },});
const themes = { default: undefined, dark: DARK_THEME, grape } as const;
export default function ViewerTheme() { const [name, setName] = useState<keyof typeof themes>('grape'); return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <label style={{ padding: 8, background: '#fff', font: '13px system-ui' }}> Theme{' '} <select value={name} onChange={(e) => setName(e.target.value as keyof typeof themes)}> {Object.keys(themes).map((t) => ( <option key={t}>{t}</option> ))} </select> </label> <div style={{ flex: 1, minHeight: 0 }}> <ReportViewer template={salesTemplate} data={salesData} theme={themes[name]} zoomMode="fitWidth" showIssues /> </div> </div> );}<script setup lang="ts">import { computed, ref } from 'vue';import { DARK_THEME, ReportViewer, themeFromMui } from '@ariana-reports/vue';import { salesData, salesTemplate } from './report-data';
// Any object shaped like a Material UI theme works.const grape = themeFromMui({ palette: { mode: 'light', primary: { main: '#7b1fa2' }, background: { default: '#f3e5f5', paper: '#ffffff' } }, shape: { borderRadius: 14 },});
const themes = { default: undefined, dark: DARK_THEME, grape } as const;const name = ref<keyof typeof themes>('grape');const theme = computed(() => themes[name.value]);</script>
<template> <div style="display: flex; flex-direction: column; height: 100%"> <label style="padding: 8px; background: #fff; font: 13px system-ui"> Theme <select v-model="name"> <option v-for="t in Object.keys(themes)" :key="t">{{ t }}</option> </select> </label> <div style="flex: 1; min-height: 0"> <ReportViewer :template="salesTemplate" :data="salesData" :theme="theme" zoom-mode="fitWidth" show-issues /> </div> </div></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 } ]}Your own toolbar
Section titled “Your own toolbar”import { ReportViewer, useViewer } from '@ariana-reports/react';import { productsData, productsTemplate } from './report-data';
// Hide the built-in toolbar and drive the viewer from your own UI through its controller.export default function ViewerController() { const { controller, state } = useViewer(); return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ display: 'flex', gap: 8, alignItems: 'center', padding: 8, background: '#fff', font: '13px system-ui' }}> <button onClick={() => controller.previousPage()}>Previous</button> <span> Page {state.pageIndex + 1} of {state.pageCount} </span> <button onClick={() => controller.nextPage()}>Next</button> <button onClick={() => controller.zoomIn()}>Zoom in</button> <button onClick={() => controller.zoomOut()}>Zoom out</button> <button onClick={() => controller.downloadPdf()} disabled={state.busy}> Download PDF </button> </div> <div style={{ flex: 1, minHeight: 0 }}> <ReportViewer controller={controller} template={productsTemplate} data={productsData} toolbar={false} zoomMode="fitWidth" /> </div> </div> );}<script setup lang="ts">import { ReportViewer, useViewer } from '@ariana-reports/vue';import { productsData, productsTemplate } from './report-data';
// Hide the built-in toolbar and drive the viewer from your own UI through its controller.const { controller, state } = useViewer();</script>
<template> <div style="display: flex; flex-direction: column; height: 100%"> <div style="display: flex; gap: 8px; align-items: center; padding: 8px; background: #fff; font: 13px system-ui"> <button @click="controller.previousPage()">Previous</button> <span>Page {{ state.pageIndex + 1 }} of {{ state.pageCount }}</span> <button @click="controller.nextPage()">Next</button> <button @click="controller.zoomIn()">Zoom in</button> <button @click="controller.zoomOut()">Zoom out</button> <button :disabled="state.busy" @click="controller.downloadPdf()">Download PDF</button> </div> <div style="flex: 1; min-height: 0"> <ReportViewer :controller="controller" :template="productsTemplate" :data="productsData" :toolbar="false" zoom-mode="fitWidth" /> </div> </div></template>{ "schemaVersion": 1, "name": "Product catalog", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "products" } ], "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": 18, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 9, "text": "Product catalog", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 10, "width": 186, "height": 5, "text": "{{ count(products) }} products · printed {{ formatDate(today(), \"d MMMM yyyy\") }}", "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": "list", "dataSource": "products", "repeatHeaderOnEachPage": true, "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 28, "height": 7, "text": "SKU", "styleName": "th" }, { "id": "h2", "type": "text", "x": 28, "y": 0, "width": 72, "height": 7, "text": "Product", "styleName": "th" }, { "id": "h3", "type": "text", "x": 100, "y": 0, "width": 34, "height": 7, "text": "Category", "styleName": "th" }, { "id": "h4", "type": "text", "x": 134, "y": 0, "width": 26, "height": 7, "text": "Price", "styleName": "th", "style": { "textAlign": "right" } }, { "id": "h5", "type": "text", "x": 160, "y": 0, "width": 26, "height": 7, "text": "In stock", "styleName": "th", "style": { "textAlign": "right" } } ] }, "detail": { "id": "row", "height": 6.5, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 28, "height": 6.5, "text": "{{ row.sku }}", "styleName": "td" }, { "id": "c2", "type": "text", "x": 28, "y": 0, "width": 72, "height": 6.5, "text": "{{ row.name }}", "styleName": "td" }, { "id": "c3", "type": "text", "x": 100, "y": 0, "width": 34, "height": 6.5, "text": "{{ row.category }}", "styleName": "td" }, { "id": "c4", "type": "text", "x": 134, "y": 0, "width": 26, "height": 6.5, "text": "{{ row.price }}", "styleName": "td", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } }, { "id": "c5", "type": "text", "x": 160, "y": 0, "width": 26, "height": 6.5, "text": "{{ row.stock }}", "styleName": "td", "style": { "textAlign": "right" }, "conditions": [ { "expression": "row.stock < 10", "style": { "color": "#b91c1c", "fontWeight": "bold" } } ] } ] }, "footer": { "id": "foot", "height": 8, "components": [ { "id": "f1", "type": "text", "x": 0, "y": 1.5, "width": 134, "height": 6, "text": "Total stock value", "styleName": "sub" }, { "id": "f2", "type": "text", "x": 134, "y": 1.5, "width": 52, "height": 6, "text": "{{ sum(rows, r => r.price * r.stock) }}", "styleName": "sub", "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" } } ] } } ]}{ "products": [ { "sku": "SKU-1000", "name": "Wireless mouse 1", "category": "Hardware", "price": 12, "stock": 0 }, { "sku": "SKU-1007", "name": "Mechanical keyboard 1", "category": "Software", "price": 49.99, "stock": 13 }, { "sku": "SKU-1014", "name": "USB-C dock 1", "category": "Services", "price": 87.98, "stock": 26 }, { "sku": "SKU-1021", "name": "Webcam HD 1", "category": "Accessories", "price": 123, "stock": 39 }, { "sku": "SKU-1028", "name": "Monitor stand 1", "category": "Hardware", "price": 160.99, "stock": 52 }, { "sku": "SKU-1035", "name": "Laptop sleeve 1", "category": "Software", "price": 18.98, "stock": 65 } ]}The visual designer
Section titled “The visual designer”import { useState } from 'react';import { ReportDesigner, type ReportTemplate } from '@ariana-reports/react';import { salesData, salesTemplate } from './report-data';
export default function DesignerBasic() { const [template, setTemplate] = useState<ReportTemplate>(salesTemplate); return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ flex: 1, minHeight: 0 }}> {/* The template prop is only the starting point; changes are reported through onChange. */} <ReportDesigner template={salesTemplate} sampleData={salesData} onChange={setTemplate} onSave={async (_template, json) => { // Send `json` to your backend here. console.log('save', json.length, 'bytes'); }} /> </div> <div style={{ padding: '4px 10px', background: '#fff', font: '12px system-ui', color: '#555' }}> Template JSON: {JSON.stringify(template).length} characters </div> </div> );}<script setup lang="ts">import { ref } from 'vue';import { ReportDesigner, type ReportTemplate } from '@ariana-reports/vue';import { salesData, salesTemplate } from './report-data';
const template = ref<ReportTemplate>(salesTemplate);
async function save(_template: ReportTemplate, json: string) { // Send `json` to your backend here. console.log('save', json.length, 'bytes');}</script>
<template> <div style="display: flex; flex-direction: column; height: 100%"> <div style="flex: 1; min-height: 0"> <!-- The template prop is only the starting point; changes are reported through the change event. --> <ReportDesigner :template="salesTemplate" :sample-data="salesData" :on-save="save" @change="template = $event" /> </div> <div style="padding: 4px 10px; background: #fff; font: 12px system-ui; color: #555"> Template JSON: {{ JSON.stringify(template).length }} characters </div> </div></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 } ]}The designer in Persian
Section titled “The designer in Persian”import { useEffect, useState } from 'react';import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';import { ReportDesigner } from '@ariana-reports/react';import { persianData, persianTemplate } from './report-data';import { loadPersianFonts } from './fonts';
// uiLocale translates the toolbar, panels and dialogs and switches them to right-to-left.export default function DesignerPersian() { // The preview's PDF export needs the font files (`preview.pdf.fonts`); they also add Vazirmatn to the font list. const [fonts, setFonts] = useState<{ fonts: FontRegistration[]; measurer: TextMeasurer }>(); useEffect(() => { loadPersianFonts().then(async (fonts) => setFonts({ fonts, measurer: await createFontMeasurer(fonts) })); }, []); if (!fonts) return null; return <ReportDesigner template={persianTemplate} sampleData={persianData} uiLocale="fa" preview={{ measurer: fonts.measurer, pdf: { fonts: fonts.fonts } }} />;}<script setup lang="ts">import { onMounted, shallowRef } from 'vue';import { createFontMeasurer, type FontRegistration, type TextMeasurer } from '@ariana-reports/core';import { ReportDesigner } from '@ariana-reports/vue';import { persianData, persianTemplate } from './report-data';import { loadPersianFonts } from './fonts';
// The preview's PDF export needs the font files (`preview.pdf.fonts`); they also add Vazirmatn to the font list.const fonts = shallowRef<{ fonts: FontRegistration[]; measurer: TextMeasurer }>();onMounted(async () => { const files = await loadPersianFonts(); fonts.value = { fonts: files, measurer: await createFontMeasurer(files) };});</script>
<template> <!-- ui-locale translates the toolbar, panels and dialogs and switches them to right-to-left. --> <ReportDesigner v-if="fonts" :template="persianTemplate" :sample-data="persianData" ui-locale="fa" :preview="{ measurer: fonts.measurer, pdf: { fonts: fonts.fonts } }" /></template>{ "schemaVersion": 1, "name": "گزارش فروش", "unit": "mm", "locale": "fa-IR", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [ { "name": "sales" } ], "styles": { "title": { "fontFamily": "Vazirmatn", "fontSize": 18, "fontWeight": "bold", "textAlign": "right" }, "th": { "fontFamily": "Vazirmatn", "fontSize": 9, "fontWeight": "bold", "color": "#fff", "backgroundColor": "#334155", "padding": 1.5, "textAlign": "right" }, "td": { "fontFamily": "Vazirmatn", "fontSize": 9.5, "padding": 1.5, "textAlign": "right", "border": { "width": 0.4, "color": "#e2e8f0", "style": "solid", "sides": [ "bottom" ] } }, "sub": { "fontFamily": "Vazirmatn", "fontSize": 10, "fontWeight": "bold", "backgroundColor": "#e2e8f0", "padding": 1.5, "textAlign": "right" } }, "reportHeader": { "id": "rh", "height": 18, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 10, "text": "گزارش فروش", "styleName": "title" }, { "id": "sub", "type": "text", "x": 0, "y": 11, "width": 186, "height": 5, "text": "{{ count(sales) }} سفارش · تاریخ گزارش: {{ formatDate(today(), \"d MMMM yyyy\", \"persian\") }}", "style": { "fontFamily": "Vazirmatn", "fontSize": 9.5, "color": "#64748b", "textAlign": "right" } } ] }, "body": [ { "kind": "dataRegion", "id": "list", "dataSource": "sales", "header": { "id": "head", "height": 7, "components": [ { "id": "h1", "type": "text", "x": 0, "y": 0, "width": 40, "height": 7, "text": "تاریخ", "styleName": "th" }, { "id": "h2", "type": "text", "x": 40, "y": 0, "width": 40, "height": 7, "text": "قیمت واحد", "styleName": "th" }, { "id": "h3", "type": "text", "x": 80, "y": 0, "width": 20, "height": 7, "text": "تعداد", "styleName": "th" }, { "id": "h4", "type": "text", "x": 100, "y": 0, "width": 36, "height": 7, "text": "کالا", "styleName": "th" }, { "id": "h5", "type": "text", "x": 136, "y": 0, "width": 50, "height": 7, "text": "مشتری", "styleName": "th" } ] }, "detail": { "id": "row", "height": 7, "components": [ { "id": "c1", "type": "text", "x": 0, "y": 0, "width": 40, "height": 7, "text": "{{ row.date }}", "styleName": "td", "format": { "type": "date", "pattern": "yyyy/MM/dd", "calendar": "persian" } }, { "id": "c2", "type": "text", "x": 40, "y": 0, "width": 40, "height": 7, "text": "{{ row.price }}", "styleName": "td", "format": { "type": "number", "decimals": 0, "thousandsSeparator": true } }, { "id": "c3", "type": "text", "x": 80, "y": 0, "width": 20, "height": 7, "text": "{{ row.qty }}", "styleName": "td" }, { "id": "c4", "type": "text", "x": 100, "y": 0, "width": 36, "height": 7, "text": "{{ row.product }}", "styleName": "td" }, { "id": "c5", "type": "text", "x": 136, "y": 0, "width": 50, "height": 7, "text": "{{ row.customer }}", "styleName": "td" } ] }, "footer": { "id": "foot", "height": 10, "components": [ { "id": "f1", "type": "text", "x": 0, "y": 2, "width": 80, "height": 7, "text": "{{ sum(rows, r => r.qty * r.price) }}", "styleName": "sub", "format": { "type": "number", "decimals": 0, "thousandsSeparator": true } }, { "id": "f2", "type": "text", "x": 80, "y": 2, "width": 106, "height": 7, "text": "جمع کل (ریال)", "styleName": "sub" } ] } } ]}{ "sales": [ { "customer": "شرکت آریا", "product": "لپتاپ", "qty": 12, "price": 485000000, "date": "2026-03-21" }, { "customer": "فروشگاه پارس", "product": "مانیتور", "qty": 30, "price": 128500000, "date": "2026-03-23" }, { "customer": "شرکت آریا", "product": "کیبورد", "qty": 40, "price": 9800000, "date": "2026-03-25" }, { "customer": "دانشگستر", "product": "هدست", "qty": 25, "price": 17400000, "date": "2026-04-01" }, { "customer": "فروشگاه پارس", "product": "وبکم", "qty": 18, "price": 12300000, "date": "2026-04-03" } ]}