React component printing with react-to-print

Print Perfect: Unleashing the Magic of react-to-print

The Gray Cat
The Gray Cat

React applications often need to print specific components or sections of a page. While browsers provide basic printing, it falls short when preserving the layout and styling of complex React components. react-to-print bridges this gap with a single hook that creates pixel-perfect printouts of any React component. With version 3.3.0, the library is leaner than ever: zero runtime dependencies, a hooks-only API, and full React 19 support.

What Changed in v3

The v3 release was a major rewrite. The old ReactToPrint component and PrintContextConsumer are gone. Everything now runs through the useReactToPrint hook, which returns a function you call to trigger printing. The content prop became contentRef, removeAfterPrint flipped to preserveAfterPrint, and onBeforeGetContent merged into onBeforePrint. The bundle shrank by 34%, and Shadow DOM support landed alongside React 19 compatibility.

Since then, v3.1 improved lazy content detection and fixed onBeforePrint behavior, v3.2 added printIframeProps for privacy and security policies, and v3.3 introduced dynamic documentTitle via functions plus a dual ESM/CJS build powered by Vite.

Key Features

  • Single hook API with zero runtime dependencies
  • Copies component DOM into a hidden iframe with all stylesheets preserved
  • Waits for images, videos, and fonts to load before printing
  • Shadow DOM support for web component content
  • Dynamic document titles via string or function
  • Custom print callbacks for Electron and other environments
  • Full TypeScript support built in
  • Works with React 16.8 through React 19

Getting Up and Running

Install the package using npm or yarn:

npm install react-to-print
# or
yarn add react-to-print

That is it. No extra dependencies, no configuration files, no bundler plugins needed.

Your First Printout

The One-Hook Wonder

The entire API is a single hook. Pass it a ref to whatever you want to print, and it gives you a function to trigger the print dialog:

import { useRef } from "react";
import { useReactToPrint } from "react-to-print";

const InvoicePage = () => {
  const contentRef = useRef<HTMLDivElement>(null);
  const handlePrint = useReactToPrint({ contentRef });

  return (
    <div>
      <div ref={contentRef}>
        <h2>Invoice #1042</h2>
        <p>Amount due: $350.00</p>
        <p>Due date: March 15, 2026</p>
      </div>
      <button onClick={handlePrint}>Print Invoice</button>
    </div>
  );
};

No wrapper components, no render props, no context consumers. Attach a ref, call the hook, wire up a button.

Styling for Paper

Print output often needs different styling than what appears on screen. Use pageStyle to inject CSS into the print iframe:

const handlePrint = useReactToPrint({
  contentRef,
  pageStyle: `
    @page {
      size: A4;
      margin: 20mm;
    }
    @media print {
      body {
        -webkit-print-color-adjust: exact;
        font-size: 12pt;
      }
    }
  `,
});

You can also use standard @media print queries in your regular stylesheets. The library copies all stylesheets into the print iframe, so your print media queries work automatically.

Dynamic Document Titles

New in v3.3.0, the documentTitle option accepts a function. This is handy when the title depends on state that changes between renders:

const handlePrint = useReactToPrint({
  contentRef,
  documentTitle: () => `Invoice-${invoiceNumber}-${new Date().toISOString().slice(0, 10)}`,
});

When a user saves the printout as a PDF, the filename will reflect the current invoice number and date.

Leveling Up Your Print Game

Async Data Loading Before Print

If your component fetches data that must be present before printing, use onBeforePrint to delay the print dialog until everything is ready:

const handlePrint = useReactToPrint({
  contentRef,
  onBeforePrint: async () => {
    await fetchLatestInvoiceData();
    await loadChartImages();
  },
  onAfterPrint: () => {
    console.log("Print dialog closed");
  },
  onPrintError: (location, error) => {
    console.error(`Print failed at ${location}:`, error);
  },
});

The hook waits for the promise returned by onBeforePrint to resolve before opening the print dialog. If something goes wrong, onPrintError catches it.

Custom Print Pipelines

The print option lets you bypass the browser's native print dialog entirely. This is particularly useful in Electron apps or when piping content to a PDF generation library:

const handlePrint = useReactToPrint({
  contentRef,
  print: async (iframe) => {
    const printWindow = iframe.contentWindow;
    if (!printWindow) return;

    const html = printWindow.document.documentElement.outerHTML;
    await sendToPdfService(html);
    showNotification("PDF generated and saved");
  },
});

Securing the Print Iframe

Version 3.2.0 introduced printIframeProps, which lets you apply security and privacy attributes to the hidden iframe:

const handlePrint = useReactToPrint({
  contentRef,
  printIframeProps: {
    sandbox: "allow-same-origin allow-scripts",
    referrerPolicy: "no-referrer",
  },
});

This is useful when your application enforces strict content security policies or when the printed content should not leak referrer information.

Shadow DOM Content

If your app uses web components with Shadow DOM, enable copyShadowRoots to ensure their content gets copied into the print iframe:

const handlePrint = useReactToPrint({
  contentRef,
  copyShadowRoots: true,
});

Print-Friendly CSS Tips

A few CSS patterns make a big difference in print quality:

@media print {
  .no-print {
    display: none;
  }

  .print-only {
    display: block;
  }

  table {
    break-inside: avoid;
  }

  h2, h3 {
    break-after: avoid;
  }
}

@page {
  size: portrait;
  margin: 15mm;
}

Use break-inside: avoid on elements like table rows and cards to prevent awkward page splits. Use break-after: avoid on headings so they stay attached to the content that follows them. For landscape reports, swap portrait for landscape in the @page rule.

Migrating from v2

If you are still on v2, the migration is straightforward. Replace the ReactToPrint component with the useReactToPrint hook, rename content to contentRef and pass a ref object directly instead of a function, move any onBeforeGetContent logic into onBeforePrint, and flip removeAfterPrint to preserveAfterPrint. The trigger prop is gone entirely since you now call the returned function yourself.

Conclusion

react-to-print continues to earn its place as the go-to printing solution for React applications. The v3 rewrite trimmed the bundle by a third while adding Shadow DOM support and React 19 compatibility. Recent releases have added dynamic document titles, iframe security controls, and a modern ESM/CJS dual build. With over a million weekly downloads, zero dependencies, and an API that fits in a single hook call, it remains the simplest path from screen to paper in the React ecosystem.