Imposia

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-dom
npm install @imposia/react react react-dom
yarn add @imposia/react react react-dom
bun add @imposia/react react react-dom

Import 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

app/preview.tsx
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.

app/preview-with-state.tsx
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.

app/export-epub.ts
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

On this page