PDFreact-print-pdf
DocsBrowser-only alpha

Sizing and alignment

How container width, page margin, and align interact — and how to make your DOM exactly fill the page.

Edit this page

react-print-pdf is a camera, not a scaler. It reads each element's pixel position from the live DOM and stamps those exact coordinates into the PDF. It never resizes your content. That makes the export pixel-faithful to what you see on screen, but it also means three independent widths are at play on every export.

The three widths

PDF page width            ── fixed by  format + orientation
                              A4 portrait  = 794 px @ 96dpi
                              A4 landscape = 1123 px
                              Letter port. = 816 px

Page content area width   ── pageWidth − marginLeft − marginRight
                              0 mm  margins → 794 px (full page)
                              10 mm margins → 718 px
                              20 mm margins → 642 px

Your container width      ── whatever your CSS says
                              <div className="w-[640px]"> → always 640 px

If your container is narrower than the content area, the leftover space is slack. The align option decides where the slack goes: "center" (default) splits it evenly, "left" pushes content to the left margin, "right" to the right margin.

If your container is wider than the content area, content gets clipped on the right. The library does not auto-shrink.

The fix: match container to content area

Use the pageContentWidth helper to size your root exportable container exactly to the page's content area, so there is no slack at all:

import { exportToPDF, pageContentWidth } from "react-print-pdf";

function Invoice() {
  const ref = useRef<HTMLDivElement>(null);
  const width = pageContentWidth({ format: "A4", margin: "10mm" }); // 718 px

  return (
    <>
      <div ref={ref} style={{ width }}>
        {/* your content fills the page exactly */}
      </div>
      <button
        onClick={() =>
          exportToPDF(ref.current!, { format: "A4", margin: "10mm" })
        }
      >
        Export
      </button>
    </>
  );
}

Now align is irrelevant — the DOM and the content area are the same width, so there's nothing to align.

When you don't know the page format up front

If you let users pick A4 vs Letter at runtime, recompute the width from the same options you pass to exportToPDF:

const opts = { format, orientation, margin };
const width = pageContentWidth(opts);

return (
  <>
    <div ref={ref} style={{ width }}>...</div>
    <button onClick={() => exportToPDF(ref.current!, opts)}>Export</button>
  </>
);

The most common bug is sizing the container from one set of options and exporting with a different set. The library does not auto-shrink your DOM, so a width / margin mismatch silently clips the right edge of the page.

Keep one options object and use it everywhere:

const pageOpts = { format: "A4", margin: "10mm" } as const;

<div ref={ref} style={{ width: pageContentWidth(pageOpts) }}>
  <Invoice />
</div>

<button onClick={() => exportToPDF(ref.current!, { ...pageOpts, ...other })}>
  Export
</button>

If the source DOM is wider than the page content area at export time, exportToPDF logs a console warning explaining what it measured, what was expected, and how to fix it. There is no silent clipping with a debugger attached.

Authoring receipts and single-page documents

If paper size doesn't matter — you just want a PDF that's exactly the size of your DOM — use pageBreak: "single":

exportToPDF(ref.current, { pageBreak: "single", margin: 0 });

The page is sized to your content's bounding box. No slack, no clipping, no worries about A4 vs Letter.

Why is align "center" by default?

Because the most common user mistake is hard-coding a container width that happens to be slightly narrower than the content area (e.g. w-[640px] on A4 with 10mm margins). With align: "left" that produces a lopsided PDF. With align: "center" the slack is split evenly so the document still looks balanced even when the user hasn't sized their root container precisely.

If you size your container with pageContentWidth(...), the alignment choice doesn't matter — there's no slack to distribute.

Summary

GoalRecipe
Exactly fill the pageSize root with pageContentWidth({ format, margin })
Center a fixed-width DOMDefault behavior (no extra config)
Left-anchor a fixed-width DOMalign: "left"
Page sized to contentpageBreak: "single"
Edge-to-edge contentmargin: 0 plus pageContentWidth({ format }) for width

On this page