Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Paged.js as a browser-side print-layout step inside a small Next.js Client Component. Render the document and data through your normal App Router (Server Component) flow, mount a known content region, then call Paged.js after that region exists in the DOM. If the library touches window or document while importing, load the pagination component with next/dynamic and ssr: false from a Client Component.

This is a practical integration pattern based on the separate Paged.js and Next.js documentation. There is no documented, tested Paged.js/Next.js version pairing, so verify the result in the browser and PDF workflow you deploy.

How the integration works

Next.js App Router routes are Server Components by default. That is useful for fetching data and rendering stable markup, but pagination needs browser APIs and a real DOM. Keep those responsibilities separate:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Server render: fetch data and render the article, invoice, report or book chapter as ordinary React markup.
  2. Client boundary: wrap the content in a narrow Client Component that owns the pagination target.
  3. Browser-only loading: if importing Paged.js evaluates browser globals, dynamically load that Client Component with ssr: false.
  4. Pagination: call the Paged.js Previewer (or the polyfill preview function) only after the target is mounted and its content is ready.

Paged.js adds the paginated preview structures while rendering; its documentation says the original HTML document is not modified. Treat pagination as a derived view, not as your source of truth.

Install the packages and create the boundary

Install Paged.js in the Next.js project:

npm install pagedjs

The following App Router example uses four files. Adjust the import paths to match your project.

1. Server page

// app/page.tsx
import PagedLoader from './PagedLoader';

export default async function Page() {
  const report = {
    title: 'Quarterly report',
    sections: [
      { heading: 'Summary', body: 'Revenue increased while support volume fell.' },
      { heading: 'Details', body: 'The appendix contains the complete operating data.' }
    ]
  };

  return (
    <main>
      <h1>{report.title}</h1>
      <PagedLoader sections={report.sections} />
    </main>
  );
}

2. Client-only dynamic loader

// app/PagedLoader.tsx
'use client';

import dynamic from 'next/dynamic';

type Section = { heading: string; body: string };

const PagedClient = dynamic(() => import('./PagedClient'), {
  ssr: false
});

export default function PagedLoader({ sections }: { sections: Section[] }) {
  return <PagedClient sections={sections} />;
}

ssr: false belongs in a Client Component. This prevents the browser-only pagination component from being rendered on the server.

3. Client pagination component

// app/PagedClient.tsx
'use client';

import { useEffect, useRef } from 'react';
import { Previewer } from 'pagedjs';

type Section = { heading: string; body: string };

export default function PagedClient({ sections }: { sections: Section[] }) {
  const sourceRef = useRef<HTMLDivElement>(null);
  const targetRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const source = sourceRef.current;
    const target = targetRef.current;
    if (!source || !target) return;

    let cancelled = false;
    target.replaceChildren();

    const run = async () => {
      const previewer = new Previewer();
      await previewer.preview(source, ['/print.css'], target);
      if (cancelled) target.replaceChildren();
    };

    run().catch((error) => {
      console.error('Paged.js preview failed', error);
    });

    return () => {
      cancelled = true;
    };
  }, [sections]);

  return (
    <section>
      <div ref={sourceRef} className="paged-source">
        {sections.map((section) => (
          <article key={section.heading}>
            <h2>{section.heading}</h2>
            <p>{section.body}</p>
          </article>
        ))}
      </div>
      <div ref={targetRef} aria-live="polite" />
    </section>
  );
}

The preview call receives the DOM content, an array of stylesheet paths and the destination element. The cancellation flag prevents a stale asynchronous run from clearing a newer result. It is implementation hygiene rather than an official Next.js hook.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Print stylesheet

/* public/print.css */
@page {
  size: A4;
  margin: 18mm 16mm;
}

body {
  font-family: system-ui, sans-serif;
  color: #111;
}

article {
  break-inside: avoid;
  margin-block: 0 12mm;
}

h2 {
  break-after: avoid;
}

.paged-source {
  display: none;
}

Use a URL that the browser can fetch for your stylesheet. If the stylesheet is under public, /print.css works in a standard Next.js deployment. Keep print-only rules out of the interactive source when they would harm the screen layout.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Using the browser polyfill instead of Previewer

The Paged.js browser polyfill can paginate automatically or wait for an explicit call. Manual mode is useful when your data, images or fonts load after the initial React render.

<script src="/paged.polyfill.js"></script>
<script>
  window.PagedConfig = { auto: false };
  window.addEventListener('load', () => {
    window.PagedPolyfill.preview();
  });
</script>

In a Next.js app, load the script with a browser-only mechanism and call window.PagedPolyfill.preview() from a Client Component after the content is mounted. Do not reference window during server rendering.

Choosing an entry path

Path Best when Control you get Trade-off
NPM Previewer Your React code decides when pagination runs DOM content, stylesheet paths, destination element and a promise for completion You must manage browser-only loading, reruns and cleanup
Browser polyfill You want the smallest browser-page integration Automatic preview or a later manual preview call Global script setup is less explicit than an imported component
Paged.js CLI Automated or server-side PDF generation A documented headless-browser route Requires a browser-capable runtime and a separate generation process

Choose Previewer when pagination is part of an interactive route. Choose the CLI when a job, build or service should create PDFs without a user initiating the browser view. The CLI still uses a headless browser, so it is not a pure server-side React renderer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Coordinate data, images and fonts

Pagination measures the DOM that exists when it runs. A page can therefore change after late content arrives. For reliable output:

  • Run after the data-dependent subtree has rendered, not merely after the route shell appears.
  • Wait for critical images to finish loading before previewing. For known images, await their load events or use an image-loading utility in the Client Component.
  • Wait for web fonts when typography affects line wrapping; otherwise headings and page breaks can move after pagination.
  • When state changes the document, start one new preview after the update. Debounce rapid edits and prevent overlapping runs.
  • Clear or replace the previous target before rendering the next preview so old pages are not mistaken for current output.

These timing rules follow from Paged.js measuring browser DOM content; they are not a prescribed Next.js lifecycle recipe.

Print CSS and browser limits

Use print declarations for page dimensions, margins, breaks, running material and image behavior. Test the exact browser and PDF path you support. Paged.js documentation notes that support for @page { size } depends on the browser, and print capabilities differ between browsers. A route that looks correct in one browser may have different margins, breaks or page sizing in another.

  • Check page size and orientation in the generated PDF, not only in the on-screen preview.
  • Inspect long tables, large images, widows and orphans, and headings near page boundaries.
  • Confirm that custom fonts are available in the generation environment.
  • Keep a representative document fixture for regression checks after upgrading Next.js, Paged.js or the browser.

Server rendering, static export and PDF jobs

Server Components can still produce the complete source document. They do not, by themselves, run Paged.js because pagination needs a browser DOM. For a user-facing preview, the Client Component approach is the natural fit. For repeatable PDF jobs, invoke the documented Paged.js CLI in a headless-browser environment and pass it a page whose assets and print CSS are reachable. Separate the job from the request path when documents are large or generation can take several seconds.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

No combined official tutorial or tested package-version matrix establishes a universal Next.js/Paged.js pairing. Pin versions in your lockfile, test after upgrades and record the browser version used for PDF generation.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Troubleshooting common failures

Symptom Likely cause Fix
window is not defined or document is not defined Paged.js was imported or executed during server rendering Move the import into a Client Component and load that component with next/dynamic using ssr: false.
Blank pagination target The preview ran before refs were populated, or the stylesheet/content URL failed Start in useEffect, verify both refs, inspect network requests and confirm the CSS path is reachable.
Pages contain old and new content Multiple asynchronous previews overlap Clear the target before each run, debounce updates and ignore or cancel stale promises.
Images overlap text or create unexpected breaks Images were not loaded when layout was measured Wait for critical image loads, then run pagination again.
Fonts change page count Web fonts arrived after preview Wait for document.fonts.ready where supported, then rerun and test the deployed font URLs.
@page size is ignored Browser print support differs Verify the browser/PDF engine, inspect its print settings and provide a tested fallback size.
CLI job cannot load assets The headless browser cannot reach relative CSS, fonts or images Serve assets from reachable URLs, check authentication and wait for network and font readiness before generating.

Performance, reliability and cost considerations

Paged.js performs layout work in a browser, so document length, image dimensions, font loading and repeated previews affect latency and memory. Keep the paginated subtree focused on the document, avoid rerunning for unrelated UI state and resize oversized source images before layout. For large batches, queue CLI jobs and cap concurrency according to the browser resources available.

Paged.js itself is open-source software; the integration has no Paged.js service fee described in its documentation. Your costs come from the browser runtime, hosting and any PDF storage or queueing you add. Measure those in your deployment rather than assuming a fixed generation time.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your real requirement is a clean screenshot or PDF of a deployed URL rather than an in-app pagination preview, ScreenshotNeo provides a single HTTP request and an MCP server for AI clients. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed; the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

See the ScreenshotNeo API documentation for options such as full-page capture, CSS-selected elements, device presets, custom CSS and JavaScript, waits, request blocking, cookies, headers, geolocation, PDF settings, caching, signed links, asynchronous webhooks and bulk capture.

One-call examples

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers take_screenshot, get_page_info and capture_pdf through MCP for Claude, Cursor and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

Frequently Asked Questions

Can a static Next.js export run Paged.js automatically?

The export can provide the HTML and assets, but pagination still has to run in a browser. Add the Client Component to the page or use the Paged.js headless-browser CLI against the exported route.

Should pagination run on every React render?

No. Trigger it only when the paginated content, its assets or relevant print settings change, and serialize runs so two previews never update the target at the same time.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is the generated PDF identical in every browser?

No guarantee is established. Browser print engines differ, including support for @page { size }; test the browser and PDF path you intend to support.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.