How to Convert HTML to PDF Using React
Tags: jspdf, webdev, react, html
Published: 2023-11-28 18:30:05

In this tutorial, you’ll learn how to convert HTML into PDF using React, one of the most popular JavaScript libraries. To achieve this, you’ll use an open source package called [jsPDF](https://parall.ax/products/jspdf), which is a client-side library that doesn’t require any server-side processing. You’ll use the latest version, [2.5.1](https://www.npmjs.com/package/jspdf). jsPDF can be used to generate reports, invoices, and tickets.

## What Can You Convert into PDF via jsPDF?

If you look at the [live demo examples][] of jsPDF, you can see it’s possible to convert images, font faces, font sizes, circles, rectangles, triangles, tables, lines, languages, and more into PDF format. You can also convert HTML into multiple pages with page breaks and add password protection and annotations. It’s also possible to change the orientation of a page to landscape or portrait.

## Setting Up a React Project

To get started, you'll use [Create React App][]. This will create a new React project with all the necessary dependencies and configuration files:

```bash
npx create-react-app convert-html-to-pdf
```

Change to the newly created directory and install the `jspdf` package through `npm` or `yarn`:

```bash
cd convert-html-to-pdf
```

```npm
npm install jspdf
```

```yarn
yarn add jspdf
```

## Using the jsPDF Library

1.Now, open the `App.js` file and import the `jspdf` package:

```js
import jsPDF from 'jspdf';
```

2.Initialize a new instance of `jsPDF`:

```js
const doc = new jsPDF();
```

jsPDF provides some options to customize a PDF. By default, it’ll use A4 paper size, portrait orientation, and millimeters as a unit of measurement.

If you want to change any of these options, you can pass an object to the constructor:

```js
const doc = new jsPDF({
	orientation: 'landscape',
	unit: 'in',
	format: [4, 2],
});
```

You can find all the available options in the jsPDF [documentation][].

## Converting HTML to PDF

jsPDF provides a method called [`html()`][] to convert HTML to PDF. It takes two arguments: the HTML element, and a callback function. Since you’re using React, to get a reference to the HTML element, use the [`useRef()`][] hook.

The `doc.save()` method takes the name of the PDF file as an argument. It’ll download the PDF file to the user’s computer:

```js
doc.html(html_element, {
	async callback(doc) {
		await doc.save('pdf_name');
	},
});
```

## Adding the Markup

To convert HTML to PDF, you need to add the markup to the page. You’ll use a report template with a button. When the button is clicked, you’ll trigger an event to generate the PDF. The `div` element will contain the HTML that you want to convert to PDF.

Create a new file called `ReportTemplate.js` and add the following code:

```js
const ReportTemplate = () => {
	const styles = {
		page: {
			marginLeft: '5rem',
			marginRight: '5rem',
			'page-break-after': 'always',
		},

		columnLayout: {
			display: 'flex',
			justifyContent: 'space-between',
			margin: '3rem 0 5rem 0',
			gap: '2rem',
		},

		column: {
			display: 'flex',
			flexDirection: 'column',
		},

		spacer2: {
			height: '2rem',
		},

		fullWidth: {
			width: '100%',
		},

		marginb0: {
			marginBottom: 0,
		},
	};
	return (
		<>
			<div style={styles.page}>
				<div>
					<h1 style={styles.introText}>
						Report Heading That Spans More Than Just One Line
					</h1>
				</div>

				<div style={styles.spacer2}></div>

				<img style={styles.fullWidth} src="photo-2.png" />
			</div>

			<div style={styles.page}>
				<div>
					<h2 style={styles.introText}>
						Report Heading That Spans More Than Just One Line
					</h2>
				</div>

				<div style={styles.columnLayout}>
					<div style={styles.column}>
						<img style={styles.fullWidth} src="photo-2.png" />
						<h4 style={styles.marginb0}>Subtitle One</h4>
						<p>
							Lorem ipsum dolor sit amet, consectetur adipiscing
							elit, sed do eiusmod tempor incididunt ut labore et
							dolore magna aliqua.
						</p>
					</div>

					<div style={styles.column}>
						<img style={styles.fullWidth} src="photo-1.png" />
						<h4 style={styles.marginb0}>Subtitle Two</h4>
						<p>
							Lorem ipsum dolor sit amet, consectetur adipiscing
							elit, sed do eiusmod tempor incididunt ut labore et
							dolore magna aliqua.
						</p>
					</div>
				</div>

				<div style={styles.columnLayout}>
					<div style={styles.column}>
						<img style={styles.fullWidth} src="photo-3.png" />
						<h4 style={styles.marginb0}>Subtitle One</h4>
						<p>
							Lorem ipsum dolor sit amet, consectetur adipiscing
							elit, sed do eiusmod tempor incididunt ut labore et
							dolore magna aliqua.
						</p>
					</div>

					<div style={styles.column}>
						<img style={styles.fullWidth} src="photo-4.png" />
						<h4 style={styles.marginb0}>Subtitle Two</h4>
						<p>
							Lorem ipsum dolor sit amet, consectetur adipiscing
							elit, sed do eiusmod tempor incididunt ut labore et
							dolore magna aliqua.
						</p>
					</div>
				</div>
			</div>
		</>
	);
};

export default ReportTemplate;
```

Here, you added some filler images to the report template. You can replace them with your own images. As for the styling, you used inline styles because jsPDF doesn’t support external stylesheets.

## Generating the PDF

Now that you have the [JSX][] in place, you can handle the button click. You’ll use the `onClick` event handler to call the `handlePDF` function.

Go back to `App.js` and add the `onClick` event handler to the button. After that, import the `useRef` hook and the reference to the HTML element:

```js
import { useRef } from 'react';
import jsPDF from 'jspdf';
import ReportTemplate from './ReportTemplate';

function App() {
	const reportTemplateRef = useRef(null);

	const handleGeneratePdf = () => {
		const doc = new jsPDF({
			format: 'a4',
			unit: 'px',
		});

		// Adding the fonts.
		doc.setFont('Inter-Regular', 'normal');

		doc.html(reportTemplateRef.current, {
			async callback(doc) {
				await doc.save('document');
			},
		});
	};

	return (
		<div>
			<button className="button" onClick={handleGeneratePdf}>
				Generate PDF
			</button>
			<div ref={reportTemplateRef}>
				<ReportTemplate />
			</div>
		</div>
	);
}

export default App;
```

The app is now ready to generate PDFs. You can run the app with `npm start` and click the button to generate the PDF.


[![Create PDFs with React to PDF](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/html-to-pdf-react-lf7qtm)

## Adding Custom Fonts

jsPDF has support for 14 standard PDF fonts. To add custom fonts, you need to use a font converter. [Navigate to this font converter][font converter] and upload `.ttf` files.

Click Choose Files to choose the fonts you want to add. After that, click Create to convert the fonts. You don’t need to modify fontName, fontStyle, or Module format.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pylp4cba55unq218pjwq.png)


The font converter will generate a JavaScript file with the provided `.ttf` file as a base64-encoded string and some code for the jsPDF. Add the generated JavaScript file to your project.

To activate the custom font, use the [`setFont()`][] method:

```js
doc.setFont('Inter-Regular', 'normal');
```

You can find the font name before you convert the font to JavaScript. If you’re using more than one font, you need to go through the same process for each font.

You can find the demo project on CodeSandbox. Feel free to fork it and play around with it. The fonts and images used in the demo project are in the `public` folder.

## Disadvantages of Using the jsPDF Library

While jsPDF is a good library for generating PDF documents in client-side JavaScript, it has some disadvantages:

- The provided <a href="https://openbase.com/js/jspdf">documentation</a> is somewhat hard to follow.
- If you want to add custom fonts, you need to use a font converter.
- The jsPDF repository seems to be a bit outdated.
- The library doesn’t support external stylesheets.


## Conclusion

In this tutorial, we looked at how to generate client-side PDFs from HTML/JSX using React. If you’re looking to add more robust PDF capabilities, PSPDFKit offers a commercial [React PDF library][library] that can easily be integrated into your web application. It comes with 30+ features that let you view, annotate, edit, and sign documents directly in your browser. Out of the box, it has a polished and flexible UI that you can extend or simplify based on your unique use case.

You can also deploy our vanilla [JavaScript PDF viewer][vanilla] or use one of our many web framework deployment options like [React.js][], [Angular][], and [Vue.js][]. To see a list of all web frameworks, start your [free trial][]. Or, [launch our demo][demo] to see our viewer in action.


[documentation]: http://raw.githack.com/MrRio/jsPDF/master/docs/jsPDF.html
[`html()`]: http://raw.githack.com/MrRio/jsPDF/master/docs/module-html.html#~html
[live demo examples]: http://raw.githack.com/MrRio/jsPDF/master/index.html
[create react app]: https://create-react-app.dev/docs/getting-started
[`useref()`]: https://reactjs.org/docs/hooks-reference.html#useref
[`setfont()`]: http://raw.githack.com/MrRio/jsPDF/master/docs/jsPDF.html#setFont
[library]: /guides/web/react/
[angular]: /blog/2021/how-to-build-an-angular-pdf-viewer-with-pspdfkit/
[react.js]: /blog/2021/how-to-build-a-reactjs-pdf-viewer-with-pspdfkit/
[vue.js]: /blog/2021/how-to-build-a-vuejs-pdf-viewer-with-pspdfkit/
[vanilla]: /blog/2021/how-to-build-a-javascript-pdf-viewer-with-pspdfkit/
[free trial]: /try/
[demo]: https://pspdfkit.com/demo/hello
[font converter]: https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html
[jsx]: https://reactjs.org/docs/introducing-jsx.html