Your first report
1. Write a template and some data
Section titled “1. Write a template and some data”Save a template as sales.template.json and your data as sales.data.json. The examples gallery has complete files to start from. A small template looks like this:
{ "schemaVersion": 1, "name": "Sales", "unit": "mm", "page": { "size": "A4", "orientation": "portrait", "margins": { "top": 12, "right": 12, "bottom": 12, "left": 12 } }, "dataSources": [{ "name": "orders" }], "reportHeader": { "id": "rh", "height": 14, "components": [ { "id": "title", "type": "text", "x": 0, "y": 0, "width": 186, "height": 10, "style": { "fontSize": 18, "fontWeight": "bold" }, "text": "{{ params.title }}" } ] }, "parameters": [{ "name": "title", "type": "string", "defaultValue": "Sales" }], "body": [{ "kind": "dataRegion", "id": "list", "dataSource": "orders", "detail": { "id": "row", "height": 7, "components": [ { "id": "customer", "type": "text", "x": 0, "y": 0, "width": 120, "height": 7, "text": "{{ row.customer }}" }, { "id": "total", "type": "text", "x": 120, "y": 0, "width": 66, "height": 7, "style": { "textAlign": "right" }, "format": { "type": "currency", "currency": "USD" }, "text": "{{ row.total }}" } ]} }]}{ "orders": [{ "customer": "Contoso", "total": 1200 }, { "customer": "Fabrikam", "total": 89.5 }] }2. Show it
Section titled “2. Show it”import { ReportViewer, type ReportTemplate } from '@ariana-reports/react';import template from './sales.template.json';import data from './sales.data.json';
export function SalesReport() { return ( <div style={{ height: 600 }}> <ReportViewer template={template as ReportTemplate} data={data} params={{ title: 'Q1 sales' }} onError={(error) => console.error(error)} /> </div> );}<script setup lang="ts">import { ReportViewer, type ReportTemplate } from '@ariana-reports/vue';import template from './sales.template.json';import data from './sales.data.json';
const typed = template as ReportTemplate;</script>
<template> <div style="height: 600px"> <ReportViewer :template="typed" :data="data" :params="{ title: 'Q1 sales' }" @error="(error) => console.error(error)" /> </div></template>That is the whole integration. The viewer generates the report, shows every page in a scrollable column, and adds zoom, print, PDF and Excel buttons.
What you get
Section titled “What you get”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 } ]}- Scroll through the pages. The page number follows the scroll position, and the toolbar buttons jump to a page.
- Change the zoom, or choose Fit width / Fit page.
- Use PDF or Excel to download the report.
- Problems in the template (such as an expression that fails) appear in the Issues panel. The rest of the report still renders.
Things to know
Section titled “Things to know”templatecan be an object or a JSON string. The report regenerates whentemplate,dataorparamschange by reference, so keep them stable (module constants,useMemo, orref).- Invalid templates do not throw; the viewer shows the validation error and calls
onError. - To generate the report yourself (for instance on a server), use
generateReport(template, data). See Without a framework.