Show a document
Open a file into an element, and control what the reader sees.
A viewer takes an element and a set of formats. Everything else — zoom, fit, which page, what a cell click does — is a setting on top of that, and every setting is addressed by the format it belongs to so two formats can want the same word without colliding.
import { createViewer } from '@genomdev/core/viewer';
import { docx, xlsx } from '@genomdev/genom/lazy';
const viewer = createViewer(element, {
formats: [docx, xlsx],
fit: 'width',
initialPage: 0,
options: {
docx: { revisions: 'markup' },
xlsx: { formulaBar: false, sheetTabs: true },
},
});
await viewer.open(file);Moving around
Page navigation, zoom and sheet selection are format-specific, so they live on the view rather than on the viewer. viewer.view is the live view, typed as the format’s own class when you know which format you opened.
import type { DocxView } from '@genomdev/docx/view';
const view = viewer.view as DocxView | undefined;
view?.goToPage(4);
view?.goToBookmark('Chapter2');
view?.setZoom(1.5);Knowing what happened
Every renderer reports on one bus. That is why the React, Vue and Angular wrappers are the same size, and why adding a format does not add a callback to anybody’s props.
viewer.on('document:open', ({ document, detection }) => {
title.textContent = document.metadata.title ?? 'Untitled';
console.log('opened as', document.format, 'because', detection?.reason);
});
viewer.on('page:change', ({ index, total }) => setPage(index + 1, total));
viewer.on('error', ({ error }) => report(error));
// Format-specific events carry their format in the name.
viewer.on('sheet:select', ({ sheet, range }) => setStatus(`${sheet}!${range}`));
// Cancelable: stop the browser following a link inside the document.
viewer.on('link:activate', ({ href, event }) => {
if (!href.startsWith('https://')) event.preventDefault();
});Opening, closing, replacing
Calling open again before the previous call settles is correct and expected — a reader picking files in quick succession does exactly that — and the older result is discarded rather than racing the newer one onto the screen.
close empties the container and releases the document. destroy does that and also drops every subscription and plugin; the instance must not be used afterwards.
Large documents
A thousand-page document opens as quickly as a five-page one, and a sheet of a million rows as quickly as one of ten. The document viewer keeps only the pages near the viewport in the DOM; the workbook viewer virtualises both axes. Neither needs configuring, and both depend on the container being scrollable.
Give the container a bounded height. A viewer inside an element that grows with its content has nothing to virtualise against, and will mount every page.
height: 80vh; overflow: auto on the element you pass in is usually the entire fix.