Build your first page
Add Imposia to a React app, render HTML as A4 pages, then print or save them as PDF.
This guide adds a paginated preview to an existing React app. When you finish, the same component will show your HTML as A4 pages and open the browser's native print flow for paper or PDF output.
Before you begin
You need React 18 or later and a client-side browser environment. Imposia does not render pages in Node.js or during server-side rendering, so mount it below your framework's client boundary.
Install the React package
pnpm add @imposia/react react react-domnpm install @imposia/react react react-domyarn add @imposia/react react react-dombun add @imposia/react react react-domImport the package stylesheet once — in this component or in your application's client entry file. Importing it more than once is harmless, but forgetting it entirely leaves the Viewer unstyled.
Render a page document
import { ImposiaPageViewer, type ImposiaPageViewerHandle } from "@imposia/react";
import { useRef } from "react";
import "@imposia/react/styles.css";
export function Preview() {
const viewer = useRef<ImposiaPageViewerHandle>(null);
return (
<>
<ImposiaPageViewer
ref={viewer}
source={{ html: "<article><h1>Hello</h1><p>Browser-native pages.</p></article>" }}
documentOptions={{ page: { size: "A4", margin: "18mm" } }}
/>
<button type="button" onClick={() => void viewer.current?.print()}>
Print / Save as PDF
</button>
</>
);
}source.html is the content to paginate, and documentOptions.page sets the sheet size and margin. The handle always points at the latest page document that finished successfully — never at one still being built.
Confirm the result
Open the component in a browser. Your HTML should appear as an A4 page inside the Viewer.
Click Print / Save as PDF. The browser's own print dialog opens for the pages currently shown, where the reader chooses a printer or Save as PDF. The method resolves once the dialog has been dispatched; it does not return PDF bytes.
Show progress and failures
The example above renders a static string, so it commits almost immediately. Real sources take time — images settle, fonts load, long documents paginate across many pages. Use useImposiaDocument when you need to show that work.
import { useImposiaDocument } from "@imposia/react";
export function Preview({ html }: { html: string }) {
const { hostRef, state } = useImposiaDocument({ source: { html } });
return (
<>
{state.status === "loading" && <p role="status">Preparing pages…</p>}
{state.status === "error" && <p role="alert">Could not paginate this document.</p>}
<div ref={hostRef} />
</>
);
}state.status is idle, loading, ready, or error. The important detail is what loading means after a first success: the previous pages stay on screen while the next version is prepared, so a spinner should sit beside the preview rather than replace it. When state.status is error, the last document that succeeded is still the one being displayed.
Optional: export an EPUB
If your product also needs a semantic, reflowable artifact, the same committed document can produce an EPUB 3.3 Blob. This is a side output — it is not part of the preview-and-print path above, and you can skip it entirely.
Metadata is required; the export rejects without a title, language, and identifier.
const blob = await viewer.current?.exportEpub({
metadata: { title: "Hello", language: "en", identifier: "urn:example:hello" },
});The method returns the Blob; connecting it to a download or upload is your application's job. EPUB output is built from the semantic source, not from the paginated page DOM, so page furniture and generated page numbers are deliberately absent.
Next steps
Load images and fonts
Your HTML cannot fetch its own resources. Implement assetResolver before adding an <img>.
The publishing model
Read this before wiring production print or export controls.
React API
Every component, hook, and imperative handle method.
Publish several documents together
Share one reading order, outline, and page sequence across entries.