Escape
HomeDocsThe viewer

The viewer

Intent

<quario-viewer> puts a compiled report on screen as pages, and wires the export buttons that turn those pages into files. Reach for it when your users should see a document before they download it, or should choose the format themselves.

Design decisions

The viewer compiles nothing. It takes a compiled report as a property and never touches the event stream. Compiling stays your application’s job, on your instance, with your registry.

It paints the same layout the PDF target writes. @quario/layout lays out preview and document against the same faces, which is why the preview breaks its pages where the document does.

The preview approximates rather than imitating. It’s a faithful page break, not a pixel-faithful print simulation. Treat it as the document’s structure on screen, not as a proof of the final raster.

Export targets are yours to choose, in your order. Hand it the targets you want buttons for, and the buttons appear in array order. A viewer given no targets exports nothing. It can hand a reader only the formats it knows a content type for: pdf, docx, xlsx and csv. A target of your own gets no button. The sheet is the layout’s either way — targets buy downloads, not the render.

A failed render resolves the mount. The element doesn’t hang or throw into your render tree. It reports through an error event and stays mounted.

The colour scheme paints chrome only. The sheet stays the document’s, because a document that changed colour with the reader’s theme would stop being the document.

The marking goes on the sheet. An unlicensed report carries the marking in the preview just as it does in an export. The viewer never shows an unmarked page for a render that would export marked.

API walkthrough

Mounting

Import @quario/viewer/register to define the element, or import QuarioViewer and define it yourself. Set properties as element properties, not attributes, because a compiled report and a font record aren’t strings.

viewer.js
import { pdf } from '@quario/pdf'

const el = /** @type {import('@quario/viewer').QuarioViewer} */ (
  document.createElement('quario-viewer')
)

/** One decision, read by the preview and by the export. */
/** @type {import('@quario/viewer').ViewerPage} */
const page = { size: 'A4', margin: 54 }

el.report = report
el.data = data
el.page = page
el.targets = [pdf({ page })]
el.filename = 'invoice-2043'

el.addEventListener('error', (event) => {
  console.error(event.detail.kind, event.detail.error)
})

document.body.append(el)

The element and the export target are two consumers of one decision, and nothing reconciles them for you. Declare the geometry once and hand it to both, as above.

Fonts

fonts takes the same record pdf({ fonts }) takes. Pass the identical object to both so the preview measures against the faces the document will embed, and hold it across renders. The record and its buffers are the identity the viewer remembers a face by, so a fresh buffer means parsing the file again.

Reacting

rendered fires when a render lands on the sheet. error carries { error, kind }. kind is mount-render before any render has landed, and update-render after. It’s export for a download the viewer couldn’t produce, and host-option for a property it rejected before rendering anything. The mounting sample above listens for it.

renderComplete resolves once the pages within reach have painted, not every page, which is what a test awaits rather than a timer. A host that reads pixels off a page far down the document finds it blank until it’s scrolled to.

Zoom and chrome

zoom takes 'fit' or a number. colorScheme takes 'light', 'dark' or 'auto' and reaches the surrounding chrome, never the sheet.

When not to use it

A server rendering a PDF into a response needs none of this. The viewer is for a browser where someone is looking. If your users only ever receive a file, render the PDF target directly and skip the element and its layout dependency.

The document, on screen, before it is a file.

npm install quario
Getting started
© 2026 quario · KvK 61815977