Skip to content

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.

All pages in one scrollable column. Only the pages you can see are rendered, so 140 rows over several pages stay fast.

viewer-basic.tsx
import { ReportViewer } from '@ariana-reports/react';
import { productsData, productsTemplate } from './report-data';
export default function ViewerBasic() {
return <ReportViewer template={productsTemplate} data={productsData} zoomMode="fitWidth" />;
}
viewer-grouping.tsx
import { ReportViewer } from '@ariana-reports/react';
import { salesData, salesTemplate } from './report-data';
export default function ViewerGrouping() {
return <ReportViewer template={salesTemplate} data={salesData} zoomMode="fitWidth" />;
}
viewer-master-detail.tsx
import { ReportViewer } from '@ariana-reports/react';
import { ordersData, ordersTemplate } from './report-data';
export default function ViewerMasterDetail() {
return <ReportViewer template={ordersTemplate} data={ordersData} zoomMode="fitWidth" />;
}
viewer-conditional.tsx
import { ReportViewer } from '@ariana-reports/react';
import { invoicesData, invoicesTemplate } from './report-data';
export default function ViewerConditional() {
return <ReportViewer template={invoicesTemplate} data={invoicesData} zoomMode="fitWidth" />;
}
viewer-html.tsx
import { ReportViewer } from '@ariana-reports/react';
import { notesData, notesTemplate } from './report-data';
export default function ViewerHtml() {
return <ReportViewer template={notesTemplate} data={notesData} zoomMode="fitWidth" />;
}

Persian: digits, Jalali dates and interface

Section titled “Persian: digits, Jalali dates and interface”
viewer-persian.tsx
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 }} />;
}
viewer-theme.tsx
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>
);
}
viewer-controller.tsx
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>
);
}
designer-basic.tsx
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>
);
}
designer-persian.tsx
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 } }} />;
}