Generating Styled PDFs from React Applications

I have been working with React and PDF generation for several years now. The initial approach most developers take is using jsPDF or react-pdf, but those libraries quickly become unwieldy when you need consistent styling across multiple pages and components. What ended up working better for my team was building a Style Guide For React Pdf system that treats PDF generation like a component library problem. The core idea is that your PDF should render from the same React components you already use elsewhere in the application. This eliminates the duplicate markup problem where your HTML layout and your PDF layout drift apart over time. When I built our first version of this, we stored all typography scales, color tokens, spacing values, and component templates in a single config file. Changes to the design system automatically propagated to generated PDFs without touching the rendering logic.

Core Architecture

We used @react-pdf/renderer as the rendering engine because it supports CSS-like styling through its own API and handles pagination, page breaks, and fonts much better than alternatives. The library converts React components into actual PDF documents client-side or server-side. I set up a style guide file called pdfStyles.js that exported constants for every visual property. Fonts were preloaded using the Font.register() method, and I embedded subsetting to keep file sizes reasonable. A typical document started as a simple export function that accepted data and returned a Document component. The real advantage became apparent when we had a client who needed letterhead, custom watermarks, and right-to-left text support all in the same PDF. Most PDF libraries struggle with bidi text because they treat the PDF format as inherently left-to-right. My workaround was to process the content through a Unicode bidirectional algorithm before passing it to the renderer. We used the rtl-css-js package combined with a post-processing step on the final output. This added about ten minutes to development time but saved us three weeks of fighting with font fallbacks later.

Styling Strategy

Typography scales in pdfStyles.js followed a modular system. I defined base font sizes in points, line heights as ratios, and color values as hex codes with opacity variables for secondary text. Every text component pulled from these constants rather than having inline styles. This meant that when the marketing team changed the heading color from #1a1a1a to #0d0d0d, the change appeared in every generated PDF within thirty seconds. Without the central style guide, I would have spent at least two days hunting down hardcoded values across multiple document templates. Page layout used a combination of the pdf renderer's predefined page sizes and a custom margin system. I wrapped every document in a component with defined sizes, then layered content inside and components. The spacing model used a four-point grid. Padding and margin values were multiples of four. This kept everything visually consistent and made it trivial to adjust overall dimensions. Changing the top margin from forty-eight points to thirty-six points was a single value update rather than a multi-file search and replace operation. One counter-intuitive insight about this approach: React-PDF does not support floating elements. If you try to position something absolutely within a page, it will not behave the way you expect from web CSS. I learned this the hard way when I tried to create a floating signature block in the bottom-right corner of a contract template. The element rendered but it did not stay anchored to the page edge during reflow. The solution was to split the layout into two columns using the flexbox capabilities that the renderer actually supports, placing the signature content in a right-aligned column that naturally sat where I needed it.

Get the Full Details

Figure 1 from A React Style Guide Library for MUI Web Apps | Semantic Scholar
Figure 1 from A React Style Guide Library for MUI Web Apps | Semantic Scholar

Component Templates

I organized reusable PDF components into a folder structure that mirrored our web component library. Headings, paragraphs, tables, footers, and cover pages each had their own file. The table component was the most complex because PDFs do not have horizontal scrolling. My approach was to make tables responsive by wrapping them in a fixed-width container and allowing the renderer to calculate column widths automatically. I set min and max widths for each column based on the expected content length. This reduced layout breakage by roughly eighty percent compared to hardcoding all column values. Data-driven sections used a repeat function that took an array of items and rendered a block for each one. This is how we handled line items on invoices and participant lists on certificates. The repeat function handled pagination automatically by detecting when a new page was needed. Without this, I would have had to manually calculate remaining space on each page and insert page-break-after styles at the right points.

Server-Side Generation

For production use, I switched from client-side rendering to a Node.js server using puppeteer to take rendered screenshots or to call the @react-pdf/renderer renderToBuffer method directly. The server approach eliminated the browser dependency and reduced generation time from about four seconds per document to under one second. We hosted the service on a small container with auto-scaling, which handled our peak load of roughly two hundred concurrent requests without issues. The trade-off was that server-side generation made debugging harder. On the client, I could open DevTools and inspect the React tree. On the server, I had to log intermediate outputs or generate test PDFs and compare them visually. I solved this by writing a local preview script that ran the same component tree in the browser but only for debugging purposes. This script bypassed the API layer entirely and hit the renderer directly, which let me iterate quickly without going through the full request cycle.

Limits and When It Fails

There are scenarios where this approach breaks down. If you need pixel-perfect fidelity to a print-ready PDF with CMYK color profiles, @react-pdf/renderer does not support that. It uses RGB color space exclusively. For print production work, you still need to hand off to InDesign or use a different pipeline. Complex mathematical notation is another area where the renderer falls short. We had one project requiring formulas with nested fractions and integrals, and the output was unacceptable. We ended up rendering those sections as images using a separate math-typesetting library and embedding them into the PDF. That added complexity and increased the risk of resolution issues on high-density displays. Large documents with hundreds of pages also expose performance bottlenecks. The renderer loads fonts into memory once per document generation, but it does not pool font resources across multiple requests on the server side. At around two hundred pages, we started seeing memory usage spike to over four hundred megabytes per generation. The fix was to chunk the document into smaller sections and merge them using a PDF manipulation library afterwards. This added a post-processing step but kept memory consumption stable.

React/JSX Style Guide for Developers - Crest Infosystems Pvt Ltd
React/JSX Style Guide for Developers - Crest Infosystems Pvt Ltd

Practical Setup Notes

Starting a new project with a Style Guide For React Pdf system takes approximately one to two days of initial setup. The first day is spent configuring the renderer, registering fonts, and building the style guide. The second day covers creating your first document template and testing it across different data sets. After that, adding new templates typically takes one to three hours depending on complexity. This is significantly faster than maintaining separate HTML and PDF versions of the same document, which I estimate took our team two to three hours per template before we adopted this approach. The package dependencies are straightforward. The main ones are @react-pdf/renderer for rendering, and optionally react-pdf for more advanced layout features in newer versions. For server-side operations, you may also need sharp or pdf-lib for post-processing. Font licensing should not be overlooked. Embedding fonts requires checking the license terms, and some fonts restrict embedding in documents distributed outside your organization.

Summary

The Style Guide For React Pdf pattern works because it applies the same component-based thinking to document generation that you already use for your user interface. The rendering engine has real limitations around layout precision and color profiles, but for most business documents—contracts, reports, certificates, invoices—it produces reliable output with minimal maintenance overhead. The key decision points are whether you generate on the client or server, how you handle pagination in data-heavy templates, and whether you need CMYK or print-quality output, in which case you should use a different toolchain altogether.