React Web Page as a PDF Template: Pagination, Headers, Footers and More
A web page can be printed to PDF file with browser or puppeteer, so it is quite possible to create a PDF template with React.
The first thing you need to know is that CSS has a special media query for printing, which is @media print
. You can use it to customize the print output.
For example, you can use it to hide some elements when printing or define page height and page margin:
@media print {
.hide-on-print {
display: none;
}
@page {
size: A4;
margin: 0;
}
}
However, while some media queries associated with @media print
, such as @bottom-center
, are not supported by browsers, they cannot be used to define PDF page headers and footers on a web page. Nevertheless, it is still possible to handle them using web standard CSS, such as by creating a customized page counter in a custom page header or footer.
Pagination is a common requirement for PDF generation. We can easily create a React component to handle pagination:
import React from 'react';
import styles from './PdfPage.less';
export type PdfPageProps = PropsWithChildren<{
className?: string;
style?: React.CSSProperties;
}>
const PdfPage: React.FC<PdfPageProps> = ({
children, // Pass page content as children in this component
className,
style
}) => {
return <div className={[styles.page, className].join(' ')} style={style}>
<div className={styles.header}>place your page header here</div>
{children}
<div className={styles.footer}>place your page footer here</div>
</div>
}
Then we define page layout in CSS:
@page {
size: A4; // use A4 paper size
margin: 0 !important; // remove page margin so that we can use the whole page
}
@media print {
.page {
padding: 20mm; // use padding to create page margin
break-inside: avoid; // avoid page break inside the page
height: calc(98vh - 40mm); // use height to create page break
}
}
.page {
position: relative; // use position relative to place page header and footer
display: flex;
flex-direction: column;
}
.header { // place header at the top of the page
position: absolute;
right: 0;
left: 0;
top: 0;
width: 100%;
}
.footer { // place footer at the bottom of the page
position: absolute;
right: 0;
left: 0;
bottom: 0;
width: 100%;
}
Then we can use it to create a PDF page:
<PdfPage>
<h1>Page 1</h1>
<p>Page 1 content</p>
</PdfPage>
It is advisable to ensure that the height of the content on each page is smaller than the height of the page itself. Otherwise, the content may be cut off and continue onto the next page. To prevent this issue, each page should be adjusted manually to ensure that the content fits within the page and does not get cut off.
Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It can be used to generate PDF files from a web page.
import puppeteer from 'puppeteer';
const webPageToPdf = async (url: string, filepath: string) => {
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto(url,
{waitUntil: 'networkidle0'} // wait until page is fully loaded
);
await page.pdf({
format: 'A4', // use A4 paper size
path: filepath, // save PDF to a file
margin: undefined // remove page margin so that we can use the whole page
});
await browser.close();
return filepath;
};
export default webPageToPdf;